BENEATH DISK OPERATIONS FOR IBM PCs AND COMPATIBLES (Full Book!)

 





















           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³           BENEATH DISK OPERATIONS           ³

           ³                                             ³

           ³         FOR IBM  PCs AND COMPATIBLES        ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ






                           Jean J. DRABBE

                       University of Brussels

                     Department of Mathematics

                      Campus Plaine - CP 211

                      1050 Brussels - BELGIUM







TRADEMARK INFORMATION





Disk Explorer is a registered trademark of Quaid Software Limited


Flu_shot+ is a registered trademark of Software Concepts Design


IBM is a registered trademark of Internation Business Machines Corporation


Intel is a registered trademark of Intel Corporation


Microsoft is a registered trademark of Microsoft Corporation


Turbo Pascal is a registered trademark of of Borland International Inc.








                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                 ³

                        ³     PREFACE     ³

                        ³                 ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ






This text is intended to conver technicalities about diskettes;

a diskette contains much more information than just data!

Understanding the extra information is required e.g.


        . to examine non standard diskettes

        . to format (and write to) non standard diskettes

        . to repair damaged diskettes


The disk controller being ultimately in charge of all read/write

operations, its capabilities will be discussed in-depth. It can

perform much more operations than generally thought.


Most of the diskette operations make use of the Direct Memory

Access (DMA) capability of the system. The processor only has to

initialize the operation; the DMA controller handles the rest.

Details about the DMA set-up will be described in due course.


I assume that readers have some familiarity with the MS-DOS

operating system, with 8086/8088 assembly language programming

and with Turbo Pascal (preferably version 4.0 or later).


I shall often refer the reader to Thom Hogan's book :


              The Programmer's PC Sourcebook

        (Reference Tables for IBM PCs and Compatibles,

                  PS/2 Machines and DOS)

                  Microsoft Press - 1988


Hogan's book is, in my opinion, the best primary source of basic

hardware and software information that is currently available.


And last, but not least :




           ÚÄÄÄÄ  Warning  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³  ONLY write-protected or scratch diskettes  ³

           ³  should be used when testing programs that  ³

           ³  involve disk operations                    ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                  ³

                        ³     CONTENTS     ³

                        ³                  ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ






  I. STANDARD DISKETTES PHYSICAL STRUCTURE


     1. Generalities

     2. Logical sector numbers

     3. Sectors reserved for the operating system

     4. The boot sector

     5. The root directory

     6. The file allocation tables

     7. The fine structure of tracks

     8. Angular positions

     9. Clock bits



 II. THE STANDARD INTERRUPT INT 13h


     1. Generalities

     2. INT 13h functions

     3. Calling INT 13h functions from Turbo Pascal

     4. Functions 0 and 1

     5. Functions 2..4

     6. Function 5

     7. The disk base table

     8. Changing entries in the disk base table

     9. Playing tricks with INT 13h



III. INSTALLING NEW INT 13h FUNCTIONS, A FIRST STEP


     1. Generalities

     2. Planning our work

     3. Turning the disk drive motor on

     4. Recalibrating the read/write head

     5. Moving the read/write head

     6. Reading CHRN fields



 IV. THE LDC READ TRACK OPERATION


     1. Generalities

     2. Direct access memory (DMA)

     3. The read track phases

     4. Experimenting with the read track operation

     5. Positioning the read/write head on the beginning of a track


  V. THE LDC FORMAT OPERATION AND OTHER LDC OPERATIONS


     1. The complete LDC format operation

     2. Aborted format operations

     3. Other LDC operations

     4. Hidden sectors



APPENDIX A   CYCLIC REDUNDANCY CODES


APPENDIX B   DISK SPACE USED BY SECTORS


APPENDIX C   THE STRANGE CASE OF N = 0






                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                 ³

                        ³    CHAPTER I    ³

                        ³                 ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³    STANDARD DISKETTES PHYSICAL STRUCTURE    ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




1. GENERALITIES


   Before a new diskette can be used with the computer, it must be

formatted (MS-DOS has an external command FORMAT which will format

diskettes). Formatting is a process that writes organizational infor-

mation on the diskette so that the operating system can read and

write files on it. Details about the "organizational" information

will be given in section 7 of this chapter.


For the time being, let us describe how a standard 5.25-inch,

double side, double density (DS/DD) diskette is organized for data

recording.

Both sides are divided into concentric circles called tracks or

cylinders ; there are 40 tracks, numbered from  0  to  39 on each

side.

Each track is further divided into segments, called sectors ; there

are 9 sectors numbered from  1  to  9  for each track.

So, the total number of sectors on a DS/DD  5.25-inch diskette is

                     2 * 40 * 9 = 720 .

The standard storage capacity of a sector is 512 bytes ( = 0.5 Kbytes)

and, therefore the storage capacity for a standard DS/DD  5.25-inch

diskette is   720 * 512 bytes = 360K bytes.


The disk drive uses two read/write heads (one for each side) to access

data on a diskette. One is called  head 0  and the other one is called

head 1.


To specify a sector one has to give three parameters :


     C :  the cylinder or track of the sector  (0 <= C <= 39) ;

     H :  the side of the disk, or equivalently the disk drive head

          to be used to access the sector  (0  or  1) ;

     R :  the sector number within the track it belongs to

          (1 <= R <= 9).


Now, what about other disk types ?

The following table describes their organization.


ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄ¿

³  size (inches) ³   5.25     ³   5.25     ³    3.5     ³    3.5     ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´

³  density       ³   double   ³    high    ³   double   ³   high     ³

³                ³   48 TPI   ³   96 TPI   ³   135 TPI  ³            ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´

³  sides         ³     2      ³     2      ³     2      ³     2      ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´

³  tracks        ³            ³            ³            ³            ³

³   per  side    ³    40      ³    80      ³    80      ³    80      ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´

³  sectors       ³            ³            ³            ³            ³

³   per track    ³     9      ³    15      ³     9      ³    18      ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´

³  sectors       ³            ³            ³            ³            ³

³   per disk     ³    720     ³    2400    ³    1440    ³    2880    ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´

³  bytes         ³            ³            ³            ³            ³

³   per sector   ³    512     ³    512     ³    512     ³    512     ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ´

³  bytes         ³            ³            ³            ³            ³

³   per disk     ³    360K    ³    1.2M    ³    720K    ³   1.44M    ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÙ




From now on, our discussion will be restricted to 360K (5.25-inch /

DS/DD) disks. This is not a real loss of generality because the

adaptation to other disk types is straightforward.



2. LOGICAL SECTOR NUMBERS


   Remember, so far we need three parameters  C  H  R  to specify a

sector. There is another way of doing it : using logical sector

numbers (lsn) in the range  0..719.


   lsn  0  is assigned to sector  C = 0   H = 0   R = 1

   lsn  1  is assigned to sector  C = 0   H = 0   R = 2

   ...  .  .. ........ .. ......  .....   .....   .....

   lsn  8  is assigned to sector  C = 0   H = 0   R = 9

   lsn  9  is assigned to sector  C = 0   H = 1   R = 1

   lsn 10  is assigned to sector  C = 0   H = 1   R = 2

   ... ..  .. ........ .. ......  .....   .....   .....

   lsn 17  is assigned to sector  C = 0   H = 1   R = 9

   lsn 18  is assigned to sector  C = 1   H = 0   R = 1

   ... ..  .. ........ .. ......  .....   .....   .....


More generally :


   lsn = (C * 18) + (H * 9) + R - 1


and conversely :


   C = lsn div 18

   H = (lsn div 9) mod 2

   R = (lsn mod 9) + 1


For readers who are not afraid of elementary mathematics :

lsns correpond to a lexicographic ordering of sectors according to

(C,H,R).




3.  SECTORS "RESERVED" FOR THE OPERATING SYSTEM


    Even when a diskette is formatted without the  /S  option, not all

of the 720 sectors are available to the user for file storage.

The operating system wants its share :


ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³   sector  lsn 0  (C = 0   H = 0   R = 1)  is the boot sector       ³

³--------------------------------------------------------------------³

³   sector  lsn 1 and lsn 2  (C = 0   H = 0   R = 2,3) are for       ³

³           the first File Allocation Table  (FAT1)                  ³

³--------------------------------------------------------------------³

³   sector  lsn 3 and lsn 4  (C = 0   H = 0   R = 4,5) are for       ³

³           the second File Allocation Table  (FAT2)                 ³

³--------------------------------------------------------------------³

³   sector  lsn 5 to lsn 11   (C = 0   H = 0   R = 6)    to          ³

³                             (C = 0   H = 1   R = 3)    are         ³

³           for the root directory                                   ³

ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³      see sections 4 - 6  for information about these sectors       ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



The operating system is not too greedy ; it wants a share consisting

of 12 sectors (6 Kbytes) and therefore  360Kbytes - 6 Kbytes =

354 Kbytes are available to the user (starting from lsn 12).


A cluster is a group of two consecutive sectors ("consecutive sectors"

means "sectors whose lsns are consecutive numbers"). They are numbered

from  2  to  355.


cluster  2  consists of sectors  lsn 12  and  lsn 13

cluster  3  consists of sectors  lsn 14  and  lsn 15

....................................................


More generally :


cluster  k  consists of sectors  lsn  (k - 2) * 2 + 12

                        and      lsn  (k - 2) * 2 + 13  .


Clusters are allocation units used to assign disk space to files.

The number of clusters needed to write a file of size  s  (bytes)

is  (s + 1023) div 1024 .




4. THE BOOT SECTOR


   Sector  lsn 0  (C = 0   H = 0   R = 1)  is the boot sector.

It contains :


(a)  a bootstrap program which reads the first root directory sector

     to see if the (hidden files)  IO.SYS  and  MSDOS.SYS  are present

     (if the system uses PC-DOS these files are named  IBMBIO.COM

and  IBMDOS.COM). If they are present  IO.SYS  is loaded into memory

and executed. Otherwise the bootstrap displays the (well known)

message :

           Non-System disk or disk error

           Replace and strike any key when ready  .


(b)  a parameter table starting at the offset 0Bh :


ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄ¿

³ offset ³ length ³            description                ³ standard ³

³ (hex)  ³        ³                                       ³  value   ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  0Bh   ³  word  ³  number of bytes per sector           ³ 200h=512 ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  0Dh   ³  byte  ³  number of sectors per cluster        ³    2     ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  0Eh   ³  word  ³  number of reserved (boot) sectors    ³    1     ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  10h   ³  byte  ³  number of FATs                       ³    2     ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  11h   ³  word  ³  number of root directory entries     ³  70h=112 ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  13h   ³  word  ³  total number of sectors on disk      ³ 2D0h=720 ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  15h   ³  byte  ³  media descriptor or disk ID byte (*) ³   FDh    ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  16h   ³  word  ³  number of sectors per FAT            ³    2     ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  18h   ³  word  ³  number of sectors per track          ³    9     ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  1Ah   ³  word  ³  number of heads                      ³    1     ³

ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄ´

³  1Ch   ³  word  ³  number of hidden sectors             ³    0     ³

ÀÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÙ


    (*)  see  Hogan's Sourcebook (2.37) for non 360K disks ID byte



Remark : I think that it is instructive to spend a couple of hours to

         disassemble the contents of the boot sector and I advice the

         reader to do it.




5. THE ROOT DIRECTORY


   The root directory occupies 7 sectors. It contains 112 entries ;

each of them is composed of 32 bytes (see Hogan's Sourcebook (2.33)

for information about directory entries layout).


If the disk is bootable, the first directory entry describes the file

IO.SYS  and the second directory entry describes the file  MSDOS.SYS.


Bytes  1Ah  and  1Bh  of a directory entry indicate the first cluster

assigned to the file.

What about the other clusters (if any) ?

The File Allocation Table (to be discussed in the next section) is to

be used to locate them.


When a file is erased its directory entry is left intact except for

the first byte (the first character of the file name) which is

changed into  E5h . Of course, such a directory entry can be

overwritten if additional files are stored to the diskette.


Note that there are no sectors reserved for subdirectories and that

subdirectoy entries have the same format as root directory entries.




6. THE FILE ALLOCATION TABLES (FATs)


   There are two File Allocation Tables occupying two sectors each.


Under normal circumstances, both are identical.

If they are not, the situation is quite often a nightmare (except if

it is known for sure that only one is corrupted) because the FATs

contain vital information about cluster allocation to files.


For the sake of keeping explanations as simple as possible (I hope!)

we need an example. Here is a hexadecimal dump of the (first) FAT of

a disk (1024 = 400h bytes) :



                    0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F


           0000    FD FF FF 03 40 00 05 60 00 07 80 00 09 A0 00 0B

           0010    C0 00 0D E0 00 0F 00 01 11 F0 FF 13 40 01 15 60

           0020    01 17 80 01 19 A0 01 1B C0 01 1D E0 01 1F 00 02

           0030    21 20 02 23 40 02 25 60 02 27 80 02 29 A0 02 2B

           0040    C0 02 2D F0 FF 2F 00 03 31 20 03 33 40 03 35 60

           0050    03 37 80 03 39 A0 03 3B C0 03 3D E0 03 3F 00 04

           0060    41 20 04 43 40 04 45 F0 FF FF 8F 04 49 F0 FF 4B

           0070    C0 04 4D E0 04 4F 00 05 51 20 05 53 F0 FF 55 60

           0080    05 57 F0 FF 59 A0 05 5B F0 FF 5D E0 05 5F 00 06

           0090    61 20 06 63 F0 FF 65 60 06 67 80 06 69 A0 06 6B

           00A0    C0 06 6D E0 06 6F 00 07 71 20 07 FF 4F 07 75 60

           00B0    07 77 80 07 79 A0 07 7B C0 07 7D F0 FF 7F 00 08

           00C0    FF 2F 08 83 40 08 85 60 08 87 80 08 89 A0 08 8B

           00D0    C0 08 8D E0 08 FF 0F 09 91 20 09 93 40 09 95 60

           00E0    09 97 F0 FF 99 A0 09 9B C0 09 9D E0 09 9F 00 0A

           00F0    FF FF FF A3 40 0A A5 60 0A A7 80 0A FF AF 0A FF

           0100    CF 0A AD E0 0A AF 00 0B B1 20 0B B3 40 0B B5 60

           0110    0B B7 80 0B B9 A0 0B FF CF 0B BD E0 0B BF 00 0C

           0120    C1 20 0C C3 40 0C C5 60 0C C7 80 0C C9 A0 0C CB

           0130    C0 0C CD E0 0C CF 00 0D D1 20 0D D3 40 0D D5 60

           0140    0D D7 80 0D D9 A0 0D DB C0 0D DD E0 0D DF 00 0E

           0150    E1 20 0E E3 40 0E E5 F0 FF E7 80 0E E9 A0 0E EB

           0160    C0 0E ED E0 0E FF 0F 0F F1 20 0F F3 40 0F F5 60

           0170    0F F7 F0 FF F9 A0 0F FB C0 0F FD F0 FF FF F0 FF

           0180    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

           0190    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00


           ....    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..


           03F0    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00




The first three bytes of the FAT do not seem to be of any use.


Remember that there are  354  clusters (numbered from  2  to  163h).

The FAT provides a 12-bit entry for each cluster (12-bit numbers can

be written as 3-digit hexadecimal numbers).


The following algorithm may be used to get the entry for cluster k :


ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³  (i)  get the word w at the offset   (k * 3) div 2                 ³

³           (keeping in mind that words are stored byte swapped,     ³

³           i.e. least significant byte first)                       ³

³                                                                    ³

³  (ii) if k is even then get rid of the first hex digit of w        ³

³       if k is odd  then get rid of the last  hex digit of w        ³

ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



Using the algorithm and the sample FAT above, one get the results :



                  cluster no   ³   12-bit entry

               ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                     002h      ³      003h

                     003h      ³      004h

                     004h      ³      005h

                     005h      ³      006h

                     006h      ³      007h

                     007h      ³      008h

                     008h      ³      009h

                     009h      ³      00Ah

                     00Ah      ³      00Bh

                     00Bh      ³      00Ch

                     00Ch      ³      00Dh

                     00Dh      ³      00Eh

                     00Eh      ³      00Fh

                     00Fh      ³      010h

                     010h      ³      011h

                     011h      ³      FFFh

                     ....      .      ....

                     100h      ³      000h

                     ....      .      ....



The values of the FAT  12-bit entries are interpreted as follows :



   ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

   ³     value      ³                 meaning                    ³

   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

   ³     000h       ³  cluster available (i.e. unused cluster)   ³

   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

   ³   FF0h..FF6h   ³  reserved cluster                          ³

   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

   ³     FF7h       ³  cluster marked bad                        ³

   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

   ³   FF8h..FFFh   ³  last cluster of file                      ³

   ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

   ³   002h..163h   ³  next cluster in file                      ³

   ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



Now, using the directory (or subdirectory) entry for a file and the

FAT, it is quite easy to trace the chain of cluster used by that file.


For example, the first root directory entry of the disk from which the

sample FAT above comes from is for the (standard system) file IO.SYS.

The first directory entry shows that the starting cluster for IO.SYS

is cluster  2. Tracing through the FAT, one realizes that


   the 2nd cluster for IO.SYS is cluster  3  (because the 12-bit entry

                                             for cluster  2  is  3)

   the 3rd cluster for IO.SYS is cluster  4  (because the 12-bit entry

                                             for cluster  3  is  4)

   ...................................................................

   the last cluster for IO.SYS is cluster  11h

                                             (because the 12-bit entry

                                             for cluster  11h  is 0) .



So, IO.SYS occupies contiguous clusters (as required by the bootstrap

program). For other files there is no contiguity requirement.



When a file is erased, all its clusters are freed (i.e. the correspon-

ding FAT  12-bit entries are changed into 000).




7. THE FINE STRUCTURE OF TRACKS


   When access is given to a disk, it rotates quite fast ; its speed

is 300 rpm (in other words, only  60/300 = 0.2 second is required to

perform a complete revolution).

The data transfer rate is  250Kbits/second (therefore  8/250000 =

32 microseconds are required to read/write a byte).


The sector (512 data bytes) is the fundamental unit of disk informa-

tion.

When a sector read/write operation is performed, the read/write head

is mechanically positioned to the proper track. Now, the disk

controller has to find the location of the sector to be used.

This can be done because, in addition to its 512 data bytes, each

sector includes a certain amount of overhead information which

provides sector identification bytes.


The analysis of the fine structure of sectors (to be described below)

also reveals the presence of a gap. This gap provides both an interval

for switching the drive electronics from reading or writing and

compensation for rotational speed.


It turns out that each sector actually uses  574  bytes!

                   The fine structure of a sector


ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³   00    ³                                                         ³

³   ..    ³           12 bytes of 00                                ³

³   00    ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   A1h   ³                                                         ³

³   A1h   ³           3 bytes of A1h                                ³

³   A1h   ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   FEh   ³           1 byte of FEh                                 ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³    C    ³         Cylinder No          (1 byte)                   ³

³    H    ³         Head No              (1 byte)                   ³

³    R    ³         Sector No            (1 byte)                   ³

³    N    ³         data size byte       (1 byte)      (*)          ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   CRC1  ³         2 Cyclic Redundancy Check bytes                 ³

³   CRC2  ³                                            (**)         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   4Eh   ³   G                                                G    ³

³   ..    ³   A             22 bytes of 4Eh                    A    ³

³   4Eh   ³   P                                                P    ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   00    ³                                                         ³

³   ..    ³           12 bytes of 00                                ³

³   00    ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   A1h   ³                                                         ³

³   A1h   ³           3 bytes of A1h                                ³

³   A1h   ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   FBh   ³           1 byte of FBh                                 ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   data  ³           512 bytes                                     ³

³  bytes  ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   CRC3  ³         2 Cyclic Redundancy Check bytes                 ³

³   CRC4  ³                                            (**)         ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ


(*)   the standard value of N is 2, meaning that there are

      128*2^N = 512 data bytes ;


(**)  CRCs are used to detect errors ; as some mathematics is involved,

      they will be discussed in Appendix A.

Although tracks are circles they all have a starting point. This fact

needs some explanation :

There is a hole in a diskette near the central hub (index hole). While

the diskette rotates a photo-sensor detects its passage and sends a

signal to the controller defining the start of track information.


Whe are now ready to describe the fine structure of a track.



                   The fine structure of a track


ÚÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

³   4Eh   ³                                                         ³

³   ..    ³           80 bytes of 4Eh                               ³

³   4Eh   ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   00    ³                                                         ³

³   ..    ³           12 bytes of 00                                ³

³   00    ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   C2h   ³                                                         ³

³   C2h   ³           3 bytes of C2h                                ³

³   C2h   ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   FCh   ³           1 byte of FCh                                 ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   4Eh   ³                                                         ³

³   ..    ³           50 bytes of 4Eh                               ³

³   4Eh   ³                                                         ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ sector  ³                                                         ³

³    1    ³           574 bytes                                     ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   4Eh   ³   G             80 bytes of 4Eh                    G    ³

³   ..    ³   A                                                A    ³

³   4Eh   ³   P       gap between sectors 1 and 2              P    ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ sector  ³                                                         ³

³    2    ³           574 bytes                                     ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   4Eh   ³   G             80 bytes of 4Eh                    G    ³

³   ..    ³   A                                                A    ³

³   4Eh   ³   P       gap between sectors 2 and 3              P    ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

/         /                                                         /

/         /                                                         /

/         /                                                         /

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³ sector  ³                                                         ³

³    9    ³           574 bytes                                     ³

ÃÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

³   4eh   ³           bytes of 4Eh                                  ³

³   ..    ³                                                         ³

³   4Eh   ³           to end of track                               ³

ÀÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




8. ANGULAR POSITIONS


   We already know that it takes  0.2 second for a diskette to perform

a complete revolution and that the transfer rate is  250Kbits/second.

Therefore a track holds  * about *

            250000 * 0.2 / 8 = 6250 bytes

(9 * 512  data bytes and organizational bytes). We said  * about *

because the disk speed can vary (the drive electronics can cope with

small variations of the rotational speed).


So, a track can be regarded as an   array[0..6249] of byte .

Looking at the above table one realizes that


      sector 1  starts at the offset  146

      sector 2  starts at the offset  146 + 654


and, more generally :


      sector R  starts at the offset  146 + (R - 1) * 654 .


Let us define the angular position (expressed in degrees) of the byte

at offset  i  by the formula :


                    i * 360 / 6250 .


For programming reasons (to be discussed later on), it is easier (and

more reliable) to locate the  CHRN  field of a sector (rather than

its starting point).


The  CHRN  field of sector 1 starts at the offset 162 and, more

generally the  CHRN  field of sector  R  starts at the offset :


                 162 + (R - 1) * 654 .


Thus we have :


              sector     ³       angular position of CHRN

                         ³       field (degrees)

           ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                1        ³      about      9

                2        ³      about     47

                3        ³      about     85

                4        ³      about    122

                5        ³      about    160

                6        ³      about    198

                7        ³      about    235

                8        ³      about    273

                9        ³      about    311



We have devoted a section to angular positions because some disk

utilities (e.g. Disk Explorer - Quaid Software Ltd) provide the user

with such information.


9. CLOCK BITS


   Of course, any write operation turns out to write bits to the

diskette. For example, writing two (consecutive) bytes of  CBh

amounts to writing the sequence of (standard) bits :


                1 1 0 0 1 0 1 1 1 1 0 0 1 0 1 1


For technical reasons (aimed at storage efficiency) the disk drive

technology adds extra bits (clock bits) between each pair of standard

bits.

The clock bit is  1  between two  0  bits and  0  between any other

pair of bits.

So, in the example given above


standard bits        1 1 0 0 1 0 1 1 1 1 0 0 1 0 1 1

clock bits            0 0 1 0 0 0 0 0 0 0 1 0 0 0 0


the actual recording is    1 0 1 0 0 1 0 0 1 0 0 0 1 0 1 0 1 0 1  ...


There are exceptions to the rule on clock bits :


  the 6 bytes of  A1h  in the fine structure of a sector

                          (see section 7)


  the 3 bytes of  C2h  in the fine structure of a track

                          (see section 7)


contain some "wrong" clock bits (some  1  clock bits are changed to 0).



It is (of course) quite easy to read the (512 * 9) data bytes on a

track.



What about reading  * all *  the bytes on a track ?

Although the disk controller is able to read organizational bytes, it

does not mean that the programmer can easily have access to non data

bytes. The disk controller acts like a black box within the computer,

executing procedures of its own and revealing (through ports)  * only

some *  of its results to the computer (just as local variables are

not accessible from the main program in Pascal).

If one turns to non standard (tricky) reading methods, the results are

partially unreliable. This is because shifts can occur and clock bits

rather than normal bits are read.




                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                  ³

                        ³    CHAPTER II    ³

                        ³                  ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³         THE STANDARD INTERRUPT 13h          ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




1. GENERALITIES


   A large variety of disk-access services is available under MS-DOS

(via  INT 21h functions) to assembly language programmers.

Roughly speaking, the Turbo Pascal disk related facilities and the

INT 21h disk services are equivalent.

With very few exceptions the INT 21h services (for assembly language

programmers) or the Turbo Pascal build-in disk facilies are best

suited for disk standard operations such as handling files.


When it comes to examine diskettes, to repair them and to spot

abnormalities used for copy protection, lower level techniques are

often required. Interrupt 13h provides useful tools. Its procedures

reside in ROM.

At first glance, its capabilities seem rather poor. Wait and see !


I do not claim that the standard ROM based INT 13h is THE disk

problem solver. In fact, the next chapters will be devoted to show

how to improve its capabilities.

One thing at a time !


Usually, while writing a program, one has not to worry about where the

global variables are located in memory when the program is executed.

Although INT 13h is not too fastidious, it requires some care about

disk data transfer areas (buffers). This is because INT 13h uses a

capability of the system known as Direct Memory Access (DMA) and has

to comply with the DMA requirements.

To explain the restriction imposed by the DMA we need some terminology.


Page 0 of memory is the 64K-segment starting at the (absolute) address

       0000h:0000h  and ending at the (absolute) address 0000h:FFFFh


----------------------------- boundary -------------------------------


Page 1 of memory is the 64K-segment starting at the (absolute) address

       1000h:0000h  and ending at the (absolute) address 1000h:FFFFh


----------------------------- boundary -------------------------------


Page 2 of memory is the 64K-segment starting at the (absolute) address

       2000h:0000h  and ending at the (absolute) address 2000h:FFFFh


----------------------------- boundary -------------------------------


......................................................................



The restriction imposed by the DMA is :


            ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

            ³                                            ³

            ³  The buffer may NOT cross a page boundary  ³

            ³                                            ³

            ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ


For example, a 20-byte buffer starting at the abslute address

0000:FFF0h is not allowed (it would start in page 0 and end in page 1).




2. INT 13h FUNCTIONS


   A total of six different functions are available through INT 13h

to access diskettes. They are :


          function 0  :  reset diskette system

          function 1  :  get diskette system status

          function 2  :  read sectors

          function 3  :  write sectors

          function 4  :  verify sectors

          function 5  :  format a track


Various registers are used to call INT 13h  (some functions do not use

all the registers shown in the following description) :



                  Register contents to call INT 13h


    ÚÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

    ³  Reg ³                      contents                     ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  AH  ³  function number (0..5)                           ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  AL  ³  number of sectors to be read/written             ³

    ³      ³  (1..9  for standard diskettes)                   ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  ES  ³  segment of buffer                                ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  BX  ³  offset of buffer                                 ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  CH  ³  track number  (normally  0..39)                  ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  CL  ³  sector number  (1..9  for standard diskettes)    ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  DH  ³  diskette side (0 or 1)                           ³

    ÃÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  DL  ³  drive number  (0 = drive A:   1 = drive B: )     ³

    ÀÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




All INT 13h calls return


      CF = 0     AH = 0               if there was no error

      CF = 1     AH = error code      if there was an error


See Hogan's Sourcebook (4.041) for information about INT 13h error

codes.


The contents of AH returned by INT 13h functions is also stored at the

absolute address  0000:0441h .




3. CALLING INT 13h FROM TURBO PASCAL


   In assembly language, it is quite simple to load registers with

values and to call an interrupt. Turbo Pascal provides an easy method

(close to assembly language) to execute an interrupt.

It uses the DOS unit (in TURBO.TPL) and a REGISTERS-type variable

(REGISTERS is defined in the interface section of the DOS unit).


Here is an example:



program example_int13h;

uses dos;


var

regs:registers;

result:byte;

buffer:array[0..buffer_size-1] of byte;        (* see remark below *)

.......


.......................................


          with regs do

          begin

            ah:=function_number;

            al:=number_sectors;

            es:=seg(buffer);

            bx:=ofs(buffer);

            ch:=track_number;

            cl:=sector_number;

            dh:=side;

            dl:=drive;

          end;


          intr($13,regs);


 (* to move the error code into  result : *)


          result:=mem[0:$441];


.......................................

.......................................

.......................................


end.



Remark : buffer may not cross a page boundary.

I confess, I often use a quick and dirty trick ; I declare buffer to

reside at a specific address in memory :

         buffer:array[0..buffer_size-1] of byte absolute $7000:0000;

(when writing small programs which do not involve pointers).

There are, of course, much better ways :

If buffer_size is  nn  , one could declare a 'large' buffer :

         buffer:array[0..2*nn-1];

and use only a part of it (to be determined by the program at

runtime).

Other methods involving heap management are also available.



4. FUNCTIONS 0 AND 1


   We shall never use function 1 (get diskette system status) because

it does not do much more than to move the contents of memory location

0000:0441h  into AL.



On the contrary, function 0 (reset diskette system) is very important.

It resets the disk controller and recalibrates the drive's read/write

head.

Function 0 should always be called after any failed read, write,

verify or format request to ensure that the error-causing condition is

cleared in the controller.

Function 0 only uses AH ( = 0 )  and   DL.

From now on, we assume that all Turbo Pascal programs calling INT 13h

include a procedure RSET (we may not use  RESET  because it is a

reserved word) :


procedure rset;

begin

regs.ah:=0;             (*  just as in the example in section 3,  *)

regs.dl:=drive;         (*  regs is a registers-type variable     *)

intr($13,regs);

end;



After any other Int 13h drive operations, something like :


error:=mem[0:$441];            (*  save error code           *)

if (error <> 0) then rset;     (*  error=0  means  no error  *)


should be executed.




5. FUNCTIONS 2..4


   From a programming point of view, function 2 (read sectors),

function 3 (write sectors) and function 4 (verify sectors) are all

similar. They use all registers shown in section 2.


The verify operation is identical to the read operation, except that

the data are thrown away rather than stored into memory.

Nevertheless it requires  ES:BX  to be initiazed properly (no page

boundary crossing). As no buffer is really needed, an absolute

declaration such as

               buffer:byte absolute $7000:0000;

will not cause any problem.

The verify operation is often used to try spotting bad areas on the

diskette.


The read operation and the write operation are data transfer

operations performing exactly what one expects.


Read, write and verify operations may involve several sectors.

For example, if the read function is called with  AL=3  CL=4

sectors  4 to 6  will be read consecutively. This means that the

buffer should be (at least) of size  512 * 3 = 1536 (for standard

diskettes).

If we want to read, write or verify more than one sector, every sector

should be on the same track and on the same side. In other words, (for

standard diskettes) :     1  <=  AL  <=  9 - CL + 1  .


As an error may appear because the drive motor has not reached a

working speed at the time of the request, it is recommended to try

read, write and verify operations three times before assuming an error

is real (and, of course, to use the reset operation between tries).


EXERCISE  Write a program that verifies all sectors on a diskette.

          [Hint : first write a procedure   verify(t,h,s,n:byte)  that

verifies  n  sectors starting with sector  s  on track t / head h ].

Such a program will turn out to be useful to spot bad sectors and non

standard sectors.




6. FUNCTION 5


   Function 5 formats  * one track *  on  * one side *  of a diskette.

All registers shown in section 2 are used except AL and CL.

The format operation writes organizational bytes (see Chapter I -

section 7) as well as data bytes (all data bytes are identical).

One may wonder why a buffer (pointed to by ES:BX) is required to

perform a format operation. In fact the buffer must hold the  CHRN

4-byte fields written on the track.

So, for a standard track, 36 bytes are required and one can use :


for i:=0 to 8 do

begin

buffer[4*i]:=track;

buffer[4*i+1]:=head;

buffer[4*i+2]:=i+1;

buffer[4*i+3]:=2;

end;


In fact the format operation  * does not check anything *  about the

values held in the buffer.

One can take advantage of this 'weakness' to write anything one likes

in the CHRN fieds. Of course, sophisticated techniques are required

when it comes to read/write sectors with strange CHRN fields.


Some copy protection methods format a track with nine identical CHRN

fields and write nine different data fields. It is obvious that it is

rather difficult to copy such a diskette.


If a track (say track 10 / head 0) is formatted with the following

CHRN fields

                  10   0   1   2

                  10   0   2   2

                  10   0   3   2

                  10   0   4   2

                  10   0   5   2

                  10   0   6   2

                  10   0   7   2

                  10   0   9*  2      *  non standard

                  10   0   8*  2      *  order


and all other tracks are formatted in the standard way, DISKCOPY will

not realize that the diskette is non standard and will agree to copy

to a standard destination disk. DISKCOMP will display : 'diskettes

compare ok ' .

This is an example of a quite simple (though 'cruel') copy protection

method.


We will learn how to read CHRN fields in Chapter III.




7. THE DISK BASE TABLE


   One can raise many questions that are unanswered in the previous

sections. For example, how does the format operation know that nine

CHRN fields are to be written on a track?


The  * dword *  at memory location  0000:0078h  is a pointer to the

11-byte Disk Base Table.

The overall operation of INT 13h is controlled by parameters in this

table.


                           Disk Base Table


    ÚÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

    ³ offset ³                  descriptions                     ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  00h   ³  first specify byte                               ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  01h   ³  second specify byte                              ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  02h   ³  wait time until motor turned off                 ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  03h   ³  number of bytes per sector code                  ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  04h   ³  number of sectors per track                      ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  05h   ³  read/write gap length                            ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  06h   ³  data length when sector length not specified     ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  07h   ³  format gap length                                ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  08h   ³  fill byte for formatting                         ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  09h   ³  head-settle time                                 ³

    ÃÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

    ³  0Ah   ³  motor start-up time                              ³

    ÀÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



The first specify byte, the second specify byte, the head-settle time

and the motor start-up time are 'technology' bytes. They should NEVER

be changed.


The wait time until motor turned off parameter specifies how long the

diskette motor is to be left running after each operation (the motor

is left on in case the diskette is needed again). The value is in

units of clock ticks (about 1/18.2 second). We will never need to

change this parameter.


The number of bytes per sector code  is used by INT 13h to determine

the actual number of data bytes per sector. If the code is  n  then

the actual number of data bytes per sector is   128 * 2^n.

The standard code  is  2  (i.e.  512  data bytes).  This parameter

often needs to be changed for non standard diskettes.

Strange things may happen when the code is  0  (see Appendix C :

'The Strange Case of N = 0').


For non standard diskettes, the number of sectors per track may be

different from the normal value 9.


The format gap length (normal value : 80 = 50h) is the number of bytes

of 4Eh written between sectors when a track is formatted (see the fine

structure of tracks in Chapter I - section 7).

It does not seem safe to use a value smaller than 12.


The read/write gap length is used when reading or writing. It tells

INT 13h how long to wait before looking for the next sector so that it

can avoid reading some of the (nonsense) bytes of 4Eh in the gap

between sectors.

The normal value is 42 = 2Ah.

Changing the read/write gap length to 8 will usually produce good

results even for non standard diskettes.

Obviously, the read/write gap must be smaller than the format gap.


We shall never need to change the value (255 = FFh) of the parameter

'data length when sector length not specified'. See Appendix C :

'The Strange Case of N = 0'.


The fill byte for formatting provides the data value that is stored

in each data byte of the sectors when a track is formatted.

It can be changed to anything.





8. CHANGING ENTRIES IN THE DISK BASE TABLE


   It is not difficult to change entries in the Disk Base Table. Good

programming practice requires that all entries are restored to their

original value before a program terminates (even in case of

termination due to a runtime error). This requirement implies that the

original values should be stored somewhere.


The following program demonstrates how to work out things in Pascal

(the reader is referred to TURBO PASCAL OWNER'S HANDBOOK for

information about exit procedures).



program ........;

................

var

table_seg,table_ofs:word;           (*  to store table address    *)

copy_table:array [0..10] of byte    (*  to store original values  *)

exit_save:pointer;

.................

.................


(* $F+ *)                           (*  compiler directive        *)

procedure restore_table;

begin

for i:=0 to 10 do mem[table_seg:table_ofs + i]:= copy_table[i];

exitproc:=exit_save;

end;

(* $F- *)                           (*  compiler directive        *)



...............................

...............................



             (* to change byte at offset  k  in table : *)


             mem[table_seg:table_ofs + k]:=......;



...............................

...............................




begin                            (*  main       *)


table_seg:=memw[0:$7a];          (*  get table  *)

table_ofs:=memw[0:$78];          (*  address    *)


for i:=0 to 10 do copy_table[i]:=mem[table_seg:table ofs + i];


                                 (*  save original table  *)


exit_save:=exitproc;

exitproc:=@restore_table;


........................

........................



end.




9.  PLAYING TRICKS WITH INT 13h


    We are now ready to experiment with some non standard diskettes

(using a scratch disk !!!).

We shall give two examples.



EXAMPLE 1 : (a) We format track 10 / head 0 with the following CHRN

                fields


             10  0  1  1

             10  0  R  2     (2  <= R  <=9)


(using the standard Disk Parameter Table).


(b) We read  track 10 / head 0 / sector 2  using the standard Disk

    Parameter Table. The error code should be  00  (no error).


(c) We read  track 10 / head 0 / sector 1  using the standard Disk

    Parameter Table. The read operation shows an error code  04

(meaning : sector not found).

The read operation first tries to locate the sector by reading CHRN

fields (until the right one is found or until all have been read).

In the present case, it is looking for  C = 10   H = 0   R = 1  (as

requested)  and   *  N = 2  *  (the value of byte 3 in the Disk

Parameter Table; it is not possible to pass a sector length code

through the registers shown in section 2).


(d) Let us change byte 3 of the Disk Parameter Table (number of bytes

    per sector code)  into  01  and try reading again  track 10 /

head 0 / sector 1.

The read operation now shows an error code  10h  (meaning :

CRC error).

This is because the track has been formatted under control of the

standard Disk Base Table and therefore each sector contains 512 data

bytes. When we read  track 10 / head 0 / sector 1  using our modified

Disk Parameter Table, only   128 * 2^1 = 256  bytes are read.

Of course, reading the first 256 bytes out of 512 is not a real

problem! We need to remember that a CRC word is written after the data

bytes when a write or format operation is executed. The CRC (word) is

a mathematical function (to be discussed in Appendix A) of the data

bytes  * and *  of the number of data bytes.

In our case, the disk controller reads the first 256 bytes and

interprets the two next bytes as a CRC; it tells INT 13h that a bad

CRC is detected.


(e) Using the same Disk Parameter Table as in (d), let us write any

    256 bytes we like to  track 10 / head 0 / sector 1 .

The write operation should show an error code  00  (no error).

A subsequent read operation shows an error code  00.

This is because the rewriting operations does not only updates data

byte; the disk controller also synthetizes a new, correct CRC.




EXAMPLE 2 : (a) Starting with a standard Disk Base Table, we change

                its byte 4 (number of sector per track) to 11.

We format  track 10 / head 0 with the following CHRN fields


                    10  0  R  2    (1  <=  R  <=  11)  .


(b) Using the same Disk Base Table as in (a), we read  track 10 /

    head 0 / sector 1 . The read operation shows an error  04

(meaning : sector not found).

If we try any other sector R with   2  <=  R  <=  10   the read

operation still shows an error  04 .

What about sector 11 ?

Surprisingly, no error is shown.

The explanation uses facts described in  Chapter 1 - sections 8 and 9.

The angular position of the CHRN field of sector 10 is

(162 + 9 * 654) * 36 / 625 = 348ø  and the angular position of the

CHRN field of sector 11 is  (162 + 6540) * 36 / 625 = 386ø .

So, during one diskette complete revolution the first ten CHRN fields

are written to the disk.

The 574 bytes for sector 11 are written while the diskette is

performing a  * second *  revolution. After these 574 bytes, bytes of

4Eh are written  * to the end *  of the track overwritting previous

disk bytes!




NOTE : When one tries to read a sector  R  and


              R  >  number of sectors per track  (byte 4 of the Disk

                                                 Base Table)

problems may occur. For such cases it is often useful to change byte 4

of the Disk Base Table to  FFh.



REMARK : INT 13h should NEVER be used to try to read a sector whose

         CHRN field is such that


                C  <>  the real track number

         or     H  <>  the real head number .


More sophisticated techniques are required to attempt such readings.




                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                   ³

                        ³    CHAPTER III    ³

                        ³                   ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³       INSTALLING NEW INT 13h FUNCTIONS      ³

           ³                                             ³

           ³                A FIRST STEP                 ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




1. GENERALITIES


   We shall devote this entire chapter to one problem :


      Read the CHRN field of all sectors present on a given track.


Such an aim might look rather limited. In fact, we will have to

introduce various techniques that are needed to solve more

sophisticated problems.

When we call the standard INT 13h to read or write a sector, we do not

need to worry about turning the disk drive motor on, about moving the

read/write head to the desired track : INT 13h takes care of such disk

drive control operations.

Before trying to install functions of our own, we must realize that

nothing comes for free ; the disk controller does exactly what it is

told to do and nothing more.

Of course, we could think of using some routines in ROM. The trouble

is that their location depend on the brand (and model) of the

computer. So, to ensure portability, we must give up the idea of

taking advantage of routines in ROM.

The reader might wonder why we want to expand INT 13h capabilities

rather than install independent services. Well, that is just a choice.

It is neither easier nor more difficult than other approaches.

Anyway, whatever the approach is, the core of the implementation

remains the same.


As we want to provide INT 13h with a new service, we need a new

function number. We choose  FFh  (almost arbitrarily).


Let us recall a well known technique.


There is a standard method to provide an interrupt with additional

services : one install a new interrupt function dispatcher using a TSR

(Terminate and Stay Resident) program. An appropriate .COM file will

do the job.

Of course, the installation part of the program should not be kept

resident ; it may be thrown away as soon as the installation is

completed.

Quite obviously, the interrupt function dispatcher should direct all

pre-existent services calls to the original dispatcher ; therefore we

need to save a pointer to the original dispatcher.


The following program demonstrates a skeleton method of implementing

a new INT 13h.




code segment

assume cs:code, ds:code

org 100h



start: jmp install


...............................

...............................



old_int13 dd ?



new_int13 proc far

cmp ah,0ffh

je new_service

jmp cs:old_int13


new_service:


;           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

;           ³                      ³

;           ³    new service       ³

;           ³    instructions      ³

;           ³                      ³

;           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




new_int13 endp



install:

mov ax,3513h                   ; get original

int 21h                        ; int vector


mov word ptr old_int13,bx      ; and save

mov word ptr old_int13+2,es    ; it


mov ax,2513h                   ; set

mov dx,offset new_int13        ; new

int 21h                        ; int vector


mov dx,offset install          ; evaluate

add dx,15                      ; amount of memory

mov cl,4                       ; memory to reserve

shr dx,cl                      ;  (in paragraphs)


mov ax,3100h                   ; terminate and

int 21h                        ; stay resident



code ends

end start



The installation part of the program above is a quick and dirty one :

it does not verify that the resident part is not already installed.




2. PLANNING OUR WORK


   Before going into details, let us remember that this chapter is

devoted to the implementation of an INT 13h new service (function FFh)

to read the CHRN field of all sectors present on a given track.

The hard work is, of course, to fill in the box marked 'new service

instructions' in the program shown in section 1.


Several steps will be required :


         (A)  Turn the disk drive motor on

         (B)  Recalibrate the read/write head

         (C)  Position the read/write head over the desired track

         (D)  Read CHRN fields


All these steps will be performed at the lowest possible level. The

computer operating system will not be kept informed of what we will

be doing.

There is only a small price to pay the operating system for keeping

it ignorant :


      ÚÄÄÄ  The price to pay the operating system  ÄÄÄÄÄÄÄÄÄÄÄÄ¿

      ³                                                        ³

      ³     Just after exiting from INT 13h / function FFh     ³

      ³     and wathever the reason for exiting is :           ³

      ³                                                        ³

      ³     a disk drive RESET (INT 13h / function 0) MUST     ³

      ³     be performed.                                      ³

      ³                                                        ³

      ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



REMARK : INT 13h / function FFh requires parameters (drive, track,

         head). Just as for the standard INT 13h, the calling program

can use registers to pass parameters.

INT 13h / function FFh also needs a data area of its own to store its

results.

This data area can also be used to save the parameters passed to

INT 13h / function FFh.

Therefore the first instructions of INT 13h / function FFh could look

like :


                     jmp       over_data


drive                db        ?

track                db        ?

head                 db        ?


results              db        ....  dup (?)


over_data:           push      ds

                     push      cs

                     pop       ds


; --  push all registers to be preserved


                     mov       drive,dl

                     mov       track,ch

                     mov       head,dh


                     ..................

                     ..................


Of course, the last instructions to be executed should return a

pointer to the results (e.g. through  ES:BX) and an error code (e.g.

through AH).



NOTE : Various procedures will be described in the next sections. Some

       (easy) work is required to put all the pieces together.

We leave that to the reader.





3. TURNING THE DISK DRIVE MOTOR ON


Only one parameter is required : the drive number (0 = drive A:

1 = drive B:).

We need to access the disk drive DIGITAL OUTPUT REGISTER (DOR) through

port 3F2h.


To turn the motor of drive 0 on, the bit setting of the DOR must be

changed into


          ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

          ³                  bit number                   ³

          ³                                               ³

          ³  7  ³  6  ³  5  ³  4  ³  3  ³  2  ³  1  ³  0  ³

          ÃÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄ´

          ³  0  ³  0  ³  0  ³  1  ³  1  ³  1  ³  0  ³  0  ³

          ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ



To turn the motor of drive 1 on, the bit setting of the DOR must be

changed into


          ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

          ³                  bit number                   ³

          ³                                               ³

          ³  7  ³  6  ³  5  ³  4  ³  3  ³  2  ³  1  ³  0  ³

          ÃÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄÅÄÄÄÄÄ´

          ³  0  ³  0  ³  1  ³  0  ³  1  ³  1  ³  0  ³  1  ³

          ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ



The byte at memory location  0:440h  holds the count down until the

disk drive motor is shut off. As we do not know for how long the disk

drive is required, it is safer to set the counter to the highest

possible value : FFh.

The computer hardware decrements this counter about 18.2 times per

second.

So, unless we need the motor to be left on for more than about

14 seconds (255/18.2), we do not need to worry any more about this

counter.


We are now ready to put it all together :


motor_on         proc     near

                 xor      ax,ax

                 mov      es,ax

                 cli

                 mov      byte ptr es:[440h],0ffh

                 sti

                 mov      cl,drive

                 mov      al,10h

                 shl      al,cl

                 or       al,cl

                 or       al,0ch

                 mov      dx,3f2h

                 out      dx,al


; -- wait for motor to come to speed  (500 milliseconds)


                 mov      al,3

                 xor      cx,cx

m1:              loop     m1

                 dec      al

                 jnz      m1

                 ret

motor_on         endp





4. RECALIBRATING THE READ/WRITE HEAD


   (a) The recalibrate operation retracts the read/write head to

       track 0.

It belongs to a group of disk controller operations which can only be

accessed at low level. Operations in this group will be used quite

often and they all require similar programming methods. Let us call

them LDC operations.

Before looking into the details of the recalibrate operation, we want

to discuss some generalities about LDC operations.


LDC operations make use of two disk controller registers :


     . the  DATA    register   (through port  3F5h)

     . the  STATUS  register   (through port  3F4h)


The disk controller operates in three phases when dealing with LDC

operations :

                  .  the command phase

                  .  the execution phase

                  .  the result phase


There is nothing to be said about the execution phase ; the disk drive

electronics performs the requested operation.


Some LDC operations have no result phase (i.e. the disk controller

does not return any result). The recalibrate operation is an example.


The general requirements of the command phase are :



      ÚÄÄÄ  command phase requirements  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

      ³                                                        ³

      ³     send an appropriate sequence of bytes to the       ³

      ³     DATA register (after receiving all bytes in the    ³

      ³     sequence the disk controller will  enter  into     ³

      ³     the execution phase)                               ³

      ³                                                        ³

      ³   --------------------  BEWARE  --------------------   ³

      ³                                                        ³

      ³     before sending EACH byte :                         ³

      ³                                                        ³

      ³     check if the DATA register is ready to accept      ³

      ³     it, i.e. make sure                                 ³

      ³                                                        ³

      ³         that bit 6 of the STATUS register is 0  (*)    ³

      ³     AND that bit 7 of the STATUS register is 1  (*)    ³

      ³                                                        ³

      ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

      ³     (*) allowing for up to 65536 retries               ³

      ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ


If the command phase fails, despite  all the allowed retries, an

error code must be IRETurned to the calling program. The calling

program should save the error code, perform a RESET operation (as

explained in section 2) and take proper action (error message, retry,

program termination).

Most command phase failures are due to program bugs!



The command phase sequence required by the recalibrate operation is

the 2-byte sequence :



               ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

               ³              ³                      ³

               ³      07      ³     drive number     ³

               ³              ³                      ³

               ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



That is all we need to know to write a recalibrate procedure :



recalibrate           proc       near

                      mov        ah,7

                      call       out_to_nec     ; send contents of AH

                                                ; to DATA register

                      jc         in_out_error

                      mov        ah,drive

                      call       out_to_nec

                      jc         in_out_error


; -- wait for head to settle (30 milliseconds)


                      mov        cx,4000h

r1:                   loop       r1


                      ret



in_out_error:         mov        ah,..          ; error code


;                     ...        .....

;                     ...        .....


;                     IRETURN TO CALLING PROGRAM


recalibrate           endp




; out_to_nec          send contents of AH to DATA register

;                     returns   CF = 0    if success

;                               CF = 1    if failure


out_to_nec            proc       near

                      clc

                      mov        dx,3f4h        ; STATUS reg port

                      xor        cx,cx

out1:                 in         al,dx

                      test       al,40h         ; bit 6 of STATUS reg

                      jz         out4

                      loop       out1

out2:                 stc

                      ret

out4:                 xor        cx,cx

out5:                 in         al,dx

                      test       al,80h         ; bit 7 of STATUS reg

                      jnz        out6

                      loop       out5

                      jmp        out2

out6:                 mov        al,ah

                      inc        dx

                      out        dx,al

                      ret

out_to_nec            endp




(b)  The recalibrate operation has no result phase. Why? Well, I do

     not know. I could not find any explanation in any manual.


How does one know the read/write head is actually retracted to

track 0 after a recalibrate operation. There is only one way : by

performing a LDC operation known as the  'sense interrupt status'

operation.


The command phase requires a 1-byte sequence to perform a sense

interrupt status operation. It is


                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³              ³

                        ³      08      ³

                        ³              ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ


Before looking into the details of the result phase for a sense

interrupt status operation, we want to discuss some generalities about

result phases.


The disk drive controller provides up to  7  result bytes (the exact

number depends on the LDC operation).

ALL result phase bytes MUST be read (the disk controller will not

accept any new command until they are read).

Let us decribe how the result bytes are to be read :



      ÚÄÄÄ  to read the result phase bytes :  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

      ³                                                        ³

      ³     read an appropriate number of bytes from the       ³

      ³     DATA register                                      ³

      ³                                                        ³

      ³   --------------------  BEWARE  --------------------   ³

      ³                                                        ³

      ³     before reading EACH byte :                         ³

      ³                                                        ³

      ³     check if the DATA register is ready to confide     ³

      ³     its secrets, i.e. make sure                        ³

      ³                                                        ³

      ³         that bit 6 of the STATUS register is 1  (*)    ³

      ³     AND that bit 7 of the STATUS register is 1  (*)    ³

      ³                                                        ³

      ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

      ³     (*) allowing for up to 65536 retries               ³

      ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ


If the appropriate number of bytes cannot be read from the DATA

register, an error code should be IRETurned to the calling program ...

(just as for command phase failure).



The number of result phase bytes is  2  for the sense interrupt status

operation.


Let us call the first one       ST0

            the second one      PCN     (Present Cylinder Number).


If a sense interrupt status operation is performed right after a

recalibrate operation then


                   PCN    should  be   00


        bit  7  of ST0    should  be    0

        bit  6  of ST0    should  be    0

        bit  5  of ST0    should  be    1

        bit  4  of ST0    should  be    0

        bit  3  of ST0    should  be    0


If any of these conditions is not satisfied, an error code should be

IRETurned to the calling program to report a recalibrate failure.

The calling program should try recalibrating three times before

assuming an error is real.



We end this section with a procedure that demonstrates how to read the

result phase bytes :



read_results        proc      near

                    mov       cx,..         ; number of bytes to read


                    mov       bx,offset some_where

rr1:                push      cx

                    call      in_from_nec

                    jnc       rr2

                    jmp       in_out_error  ; see part (a)

rr2:                mov       [bx],al

                    inc       bx

                    pop       cx

                    loop      rr1

                    ret

read_results        endp




; in_from_nec       read one byte from DATA register

;                   returns   CF = 0   byte in AL  if success

;                             CF = 1               if failure


in_from_nec         proc      near

                    clc

                    xor       cx,cx

                    mov       dx,3f4h       ; STATUS reg port

in2:                in        al,dx

                    test      al,80h        ; bit 7 of STATUS reg

                    jnz       in4

                    loop      in2

in3:                stc

                    ret

in4:                xor       cx,cx

in5:                in        al,dx

                    test      al,40h        ; bit 6 of STATUS reg

                    jnz       in6

                    loop      in5

                    jmp       in3

in6:                inc       dx

                    in        al,dx

                    ret

in_from_nec         endp




5.  MOVING THE READ/WRITE HEAD


    The disk controller provides us with a LDC operation known as the

seek operation.

The seek operation positions the read/write head over the desired

track.

Its command phase requires a 3-byte sequence



           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄ¿

           ³             ³                      ³           ³

           ³     0Fh     ³  (head * 4) + drive  ³   track   ³

           ³             ³                      ³           ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÙ



The seek operation has no result phase.

The only way to check if the read/write head is actually over the

desired track is to perform a sense interrupt status operation

(section 4(b)) ; it should return :



                   PCN    =   desired track number


        bit  7  of ST0    =      0

        bit  6  of ST0    =      0

        bit  5  of ST0    =      1

        bit  4  of ST0    =      0

        bit  3  of ST0    =      0



We shall not discuss the seek operation any further. It is quite

similar to the recalibrate operation.




6.  READING CHRN FIELDS


    The LDC operation known as 'read ID' reads a CHRN field.

To be more precise :

It keeps reading bytes until a CHRN field is found.

This DOES NOT mean that read ID tries to locate the first CHRN field

on a track. Otherwise we would never be able to read all CHRN fields!


As one guesses, to read all CHRN fields one performs read ID

operations in a loop.

Fifty readings are commonly sufficient to catch all CHRN fiels.

There is no entry in the Guiness Book of Records about CHRN fields.

So I shall just mention that the record I know about is  34  CHRN

fields.


The command phase requires a 2-byte sequence



                ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                ³             ³                      ³

                ³     4Ah     ³  (head * 4) + drive  ³

                ³             ³                      ³

                ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



The result phase provides  7  bytes :


        the first  result byte is called  ST0

        the second result byte is called  ST1

        the third  result byte is called  ST2


        the four last result bytes hold the 4-byte CHRN field read

                                                   by read ID .


The reader is referred to Hogan's Sourcebook (8.19) for a complete

description of ST0, ST1 and ST2.



As far as LDC operations are concerned that is all we need to write a

procedure that reads all CHRN fields on a track (using programming

methods described in section 4). Just a moment, please!

So far some questions are left unanswered :


(a)  Suppose that there are exactly  11  CHRN fields on the track

     being examined. If we perform  50  read ID operations, some CHRN

fields will be read  4  times and the other ones will be read  5

times. How does one find the exact number of CHRN fields?


(b)  It is natural to demand that readings should start at the

     beginning of a track rather than 'somewhere'.



The problem raised in (b) cannot be solved by standard methods

(we need tricky techniques to be covered in Chapter IV).



Let us answer question (a).

Suppose that we have got a 'high precision clock' so that immediately

after each CHRN field is found we read (and save) the 'exact' time.

After reading fifty CHRN fields we can look closely at the results

(including the time readings). If we know how long it takes a diskette

to perform a complete revolution, it becomes quite easy to determine

the exact number of CHRN fields on the track and what they are.

As we know that there are about 6250 bytes on a track, it is also

quite easy to determine approximately how many bytes there are between

two consecutive CHRN fields.


The system board contains an Intel 8253/8254 timer chip. It provides

three 16-bit counters that may be used for timing or counting in the

system. Each of the counters decrements once every 839 nanoseconds

(the frequency is 1.19318 MHz). That is more than we need!

Details about the 8253 may be found in D.J. BRADLEY's book 'Assembly

Language for the IBM Personal Computer' (Prentice-Hall).


It takes about 32 microseconds to read/write a byte from/to the

diskette. Therefore we do not really need the 8353 timer high

precision.


Other 'clocks' are available.

Let us give an example.


The system board has an Intel 8237 DMA chip. One of its functions is

to refresh memory (it constantly restores the charge in the RAM memory

cells). Refresh cycles occur every 15 microseconds (approximately).

The DMA has a word count register (accessible through port 1) reserved

for the memory refresh function. It is decremented every 15

microseconds (approximately) ; although the exact delay between two

consecutive decrements may vary from one computer to another, it is a

constant for each computer.

So the DMA chip provides us with a nice 'clock'. Reading the word

count register through port 1 is a bit tricky.

Here is a reading procedure :



read_time         proc      near

                  xor       cx,cx

rdt1:             cli


                  out       0ch,al         ; tricky part

                                           ; make DMA happy

                  in        al,1

                  mov       ah,al

                  jmp       short  rdt2

rdt2:             in        al,1

                  sti

                  or        ah,ah

                  jnz       rdt3

                  loop      rdt1

rdt3:             xchg      ah,al

                  ret                      ; time in AX

read_time         endp




We can determine how long it takes the diskette to perform a complete

revolution (whatever 'high precision clock' we use) by experimenting

on a standard diskette.


We are done!



NOTE : Interesting information about the RAM refresh cycle may be

       found in B. Roemmele's excellent article :

                  Instant Speedup for your PC

               PC Magazine  July 1988  pp 331-346.








                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                  ³

                        ³    CHAPTER IV    ³

                        ³                  ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



              ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

              ³                                      ³

              ³     THE LDC READ TRACK OPERATION     ³

              ³                                      ³

              ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




1. GENERALITIES


   We shall devote this chapter to the LDC operation known as 'read

track'. It is a very interesting operation mainly because playing

tricks with it is rather easy; in some cases, that is the only way to

read strange sectors and sometimes even organizational bytes.

Details will be given in section 4.

For the time being, let us mention that this operation can be used to

read all the data bytes on a track.


The read track operation can be implemented as a new INT 13h service,

say function FEh. About half of the hard work is already done : we

shall make use of several procedures that come with INT 13h / function

FFh  (see Chapter III).


The disk controller has no internal buffer. Therefore when it comes to

read or write data bytes, we shall make use of the Direct Memory

Access capability of the system (DMA). That is what section 2 is all

about.




2. DIRECT MEMORY ACCESS (DMA)


    The DMA provides several services. We already know about one : the

memory refresh function (see Chapter III - section 6).

Let us now examine another one.


With some devices, particularly disk drives, it is more sensible to

transfer a whole block of data at a time, rather than to transfer it

byte by byte.

The hardware is designed in such a way that the disk drive controller

transfers data to or from memory without the intervention of IN or OUT

instructions.

The IN and/or OUT instructions are still needed to initiate the

transfer, to specify things like the number of bytes to transfer and

the memory address for the transfer.

After the transfer is initiated, the disk drive controller handles all

the details and does not send the ready bit until the entire transfer

is complete.

This type of transfer is called 'Direct Memory Access Transfer'.


WHILE a DMA transfer is in progress, the processor can continue

executing other instructions. This is simply wonderful!

The instructions could be something like 'abort the transfer

immediately after 25 bytes are written to the disk'.

Although aborted operations require precise timings and are often

rather difficult to monitor, there are first-class rewards such as

writing bad CRC words and formatting only a part of a track.

More about aborted operations later on.


Here are the parameters required by the DMA :

          ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

          ³                                                 ³

          ³                 DMA  PARAMETERS                 ³

          ³                                                 ³

          ÃÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³ thru  ³                                         ³

          ³ port  ³              description                ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  0Bh  ³  DMA command code :                     ³

          ³       ³                      46h = read         ³

          ³       ³                      42h = verify       ³

          ³       ³                      4Ah = write        ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  0Ch  ³  DMA command code just as above         ³

          ³       ³  (one way to make DMA happy is to pass  ³

          ³       ³  the command code through ports         ³

          ³       ³         0Bh  and  0Ch           )       ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  05h  ³  Number of bytes to transfer MINUS 1    ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  04h  ³  Low 16 bits of transfer ABSOLUTE       ³

          ³       ³  address                                ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  81h  ³  High 4 bits of transfer ABSOLUTE       ³

          ³       ³  address                                ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  0Ah  ³  Enable DMA channel 2 by writing 2 to   ³

          ³       ³  port 0Ah (channel 2 is reserved for    ³

          ³       ³  disk operations)                       ³

          ³       ³                                         ³

          ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





          ÚÄÄÄÄ  Remember  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

          ³                                                 ³

          ³               No page crossing !                ³

          ³                                                 ³

          ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





The following procedure initializes the DMA for disk operations :




init_dma         proc    near

                 mov     al,dma_cmd_code

                 out     0ch,al

                 out     0bh,al

                 mov     ax,buffer_segment

                 mov     cl,4

                 rol     ax,cl

                 mov     ch,al

                 and     al,0f0h

                 add     ax,buffer_offset

                 jnc     no_carry

                 inc     ch

no_carry:        push    ax

                 out     4,al

                 mov     al,ah

                 out     4,al

                 mov     al,ch

                 and     al,0fh

                 out     81h,al

                 mov     ax,number_bytes

                 dec     ax

                 push    ax

                 out     5,al

                 mov     al,ah

                 out     5,al

                 pop     cx

                 pop     ax

                 add     ax,cx

                 mov     al,2

                 out     0ah,al

                 jnc     dma_end

                 jmp     dma_error

dma_end:         ret


dma_error:


;                PAGE   CROSSING

;                tell calling program

;                the requested operation

;                cannot be performed



init_dma         endp






3. THE READ TRACK PHASES


   The command phase 9-byte sequence is as follows :


          ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

          ³                                                 ³

          ³        read track command phase sequence        ³

          ³                                                 ³

          ÃÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³ byte  ³                                         ³

          ³  no   ³              description                ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  01   ³  MUST be  42h                           ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  02   ³  (4 * head) + drive                     ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  03   ³  track number                           ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  04   ³  head number                            ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  05   ³  sector number; does not seem to be of  ³

          ³       ³  any use                                ³

          ³       ³  may be set to  01                      ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  06   ³  data size code                         ³

          ³       ³  code n means  128 * 2^n bytes/sector   ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  07   ³  number of sectors/track                ³

          ³       ³  if in doubt it should be set to  FFh   ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  08   ³  read/write gap length                  ³

          ³       ³  it tells the disk controller how       ³

          ³       ³  many bytes to skip before looking for  ³

          ³       ³  the next sector so that it can avoid   ³

          ³       ³  reading some of the nonsense bytes of  ³

          ³       ³  4Eh in the gap between sectors         ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  09   ³  known as the DTL byte; does not seem   ³

          ³       ³  to be of any real use : see            ³

          ³       ³  Appendix C                             ³

          ³       ³                                         ³

          ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





The result phase provides 7 bytes. Details are given in Hogan's

Sourcebook (8.19). The result bytes MUST be read (see Chapter III

- section 4) after the entire transfer is complete. That leaves us

with the question :

           How does one know that the operation is complete?

When it is complete the disk controller invokes a diskette interrupt

which sets bit 7 of a status byte located at  0000:043Eh .

So one has to keep polling this byte until bit 7 is set then reset

the bit to 0 and continue on the next step.

The following procedure demonstrates how things can be worked out :



wait_int        proc    near

                mov     dh,2

                xor     ax,ax

                mov     es,ax

                mov     bx,43eh

                mov     cx,ax

wi1:            mov     dl,es:[bx]

                test    dl,80h

                jnz     wi2

                loop    wi1

                dec     dh

                jnz     wi1

                jmp     time_out

wi2:            and     byte ptr es:[bx],7fh

                ret


time_out:


;               time out error

;               tell the calling program


wait_int        endp





We conclude this section by recalling the steps involved in a read

track operation :


         (A) Turn the disk drive motor on     (if necessary)

         (B) Recalibrate the read/write head  (if necessary)

         (C) Position the read/write head over the desired track

                                              (if necessary)

         (D) Initialize the DMA

         (E) Command phase

         (F) Wait for the transfer to be complete

         (G) Read the result phase bytes





4. EXPERIMENTING WITH THE READ TRACK OPERATION


   Let us denote


   the number of bytes to be read (DMA parameter)         by  NB

   the number of sectors/track (command phase parameter)  by  EOT

   the sector size code (command phase parameter)         by  NN

   the read/write gap (command phase parameter)           by  GL

   the minimum of   NB  and  EOT * 128 * 2^NN             by  NR


Starting from the  * beginning *  of a track, the read track operation

reads what it thinks are  NR data bytes. It assumes that all sectors

are of size  128 * 2^NN (whether this is true or not). After reading

bytes from a sector, it looks for the next sector and reads from that

sector until NR bytes are read.


The best way of making things clear is to carry out a few experiments.


Let us start by (re)formatting a disk using the standard  FORMAT

program (the one on the System Disk).

NO files should be written to the experimentation disk!



EXPERIMENT 1


Call read track with   NB  = 1200h       track = 0

                       EOT = 9           head  = 0

                       NN  = 2

                       GL  = 2Ah


The result phase bytes do not show any error and the buffer contains

the actual 200h * 9 = 1200h data bytes on track 0/head 0.



EXPERIMENT 2


Call read track with   NB  = 1210h       track = 0

                       EOT = 9           head  = 0

                       NN  = 2

                       GL  = 2Ah


The result phase bytes show an 'end of cylinder' error. That is

because   NB > EOT * 128 * 2^NN . In other words, the calling

parameters are inconsistent : because of the value of NB the disk

controller tries to access a tenth sector although  EOT = 9 !

The buffer contains the actual 1200h data bytes just as with

experiment 1.



EXPERIMENT 3


Call read track with   NB  = 11F0h       track = 0

                       EOT = 9           head  = 0

                       NN  = 2

                       GL  = 2Ah


The result phase bytes do not show any error and the buffer contains

11F0h data bytes (all the data bytes from sectors 1 to 8 and 1F0h

bytes from sector 9).

No CRC error is reported because although only 1F0h bytes from

sector 9 are sent to the data bus, the disk controller reads

* internally *  the complete sector and then performs a CRC check.



EXPERIMENT 4


Call read track with   NB  = 2400h       track = 14

                       EOT = 9           head  = 0

                       NN  = 3

                       GL  = 8


The result bytes show       a data field CRC error

                       and  a 'no data' error.


The 'no data' error means that during the execution of the command,

the starting sector could not be found. Such an error is reported

because read track is called with  NN = 3  so that the disk controller

expects the first CHRN field to be  14 00 01 03 .

As our experimentation disk is a standard one the first CHRN field is

in fact  14 00 01 02 !

The reason for the data field CRC error will become obvious quite

soon.


Let us look at the data buffer.


Bytes 0000 to 01FF are all of the same value (format fill byte).


As NN = 3 the disk controller assumes that sectors are of data length

1024 (= 400h). Therefore when dealing with sector 1 it reads the real

512 data bytes and the next 512 disk bytes (non real data bytes)

whether they are organizational bytes or bytes from sector 2.

Assuming that we are lucky (because some non real data bytes may be

bit shifted and in error) that is exactly what we can see when looking

at the data buffer :


        bytes      ³                       are

  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   0200h and 0201h ³ the data field CRC bytes for sector 1

   0202h to  0251h ³ bytes of 4Eh (gap between sectors 1 and 2)

   0252h to  025Dh ³ bytes of OO

   025Eh to  0260h ³ bytes of A1h

   0261h           ³ byte  of FEh

   0262h to  0265h ³ the CHRN field bytes for sector 2 (14 00 02 02)

   0266h and 0267h ³ the CHRN field CRC bytes for sector 2

   0268h to  027Dh ³ bytes of 4Eh

   027Eh to  0289h ³ bytes of 00

   028Ah to  028Ch ³ bytes of A1h

   028Dh           ³ byte  of FBh

   028Eh to  03FFh ³ data bytes from sector 2


Now what is the next CHRN field found after reading the first

1024 bytes?  14 00 03 02 of course!


Some easy calculation show that :

      the real data   ³  may be found (in the data buffer)

        for sector    ³              at offset

     ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

            1         ³      0000h  to  01FFh

            2         ³      1400h  to  15FFh

            3         ³      0400h  to  05FFh

            4         ³      1800h  to  19FFh

            5         ³      0800h  to  09FFh

            6         ³      1C00h  to  1DFFh

            7         ³      0C00h  to  0DFFh

            8         ³      2000h  to  21FFh

            9         ³      1000h  to  11FFh


Remark : The bit shift condition mentioned above may occur on any

         track but it is much more likely to occur when a sector is

rewritten (the rotation rate may differ slightly from the last time we

wrote that sector so that the length of the sector will differ from

its previous length, possibly destroying a small part of the gap after

the sector or alternately allowing a few bits to survive). That is the

the reason why we make use of a newly (re)formatted disk without any

file written to it.


The reader should carry out the same experiment with track 0/head 0

(this one is rewritten by the FORMAT program as it reserves some

sectors for the operating system); more bit shifts will appear.


Sometimes things may even be worse : clock bits are read rather than

the 'real' bits.


Nevertheless, such conditions never occur when reading real data

bytes.


There is no cure when clock bits are read.

A data buffer shift procedure turns out to be very useful to deal with

bit shifts.



EXPERIMENT 5


Call read track with   NB  = 2400h       track = 14

                       EOT = 9           head  = 0

                       NN  = 3

                       GL  = 255


The result bytes show       a data field CRC error

                       and  a 'no data' error       (of course).


The following CHRN fields may be found in the data buffer :


                offset  ³  CHRN field

               ÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                0262h   ³  14 00 02 02

                0662h   ³  14 00 05 02

                0A62h   ³  14 00 08 02

                0E62h   ³  14 00 02 02

                1262h   ³  14 00 05 02

                1662h   ³  14 00 08 02

                1A62h   ³  14 00 02 02

                1E62h   ³  14 00 05 02

                2262h   ³  14 00 08 02


and


      the real data   ³  may be found (in the data buffer)

        for sector    ³              at offset

     ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

            1         ³      0000h  to  01FFh

            1         ³      0C00h  to  0DFFh

            1         ³      1800h  to  19FFh

            4         ³      0400h  to  05FFh

            4         ³      1000h  to  11FFh

            4         ³      1C00h  to  1DFFh

            7         ³      0800h  to  09FFh

            7         ³      1400h  to  15FFh

            7         ³      2000h  to  21FFh


The reason for the repeats is that the disk controller is instructed

to skip 255 bytes after reading each 1024-byte block.



EXPERIMENT 6


Let us first reformat track 14/head 0 using INT 13h/function 05. The

format function calling parameters are standard except for the

order of the CHRN fields :


                  14 00 01 02

                  14 00 03 02

                  14 00 02 02

                  14 00 04 02

                  14 00 05 02

                  14 00 06 02

                  14 00 07 02

                  14 00 08 02

                  14 00 09 02


Next, using INT 13h/function 3 let us write a message, say

'This is sector R', in each sector R  (1 <= R <= 9).


Call read track with   NB  = 1200h       track = 14

                       EOT = 9           head  = 0

                       NN  = 2

                       GL  = 2Ah


The result phase bytes show a 'no data' error due to the non standard

order of sectors.

The data buffer shows :


           This is sector 1     at  offset  0000h

           This is sector 3     at  offset  0200h

           This is sector 2     at  offset  0400h

           ................     .................


This confirms that the read track operation reads sectors in the disk

physical order.



WARNING : Read track aborts if it does not find the data mark

          3 bytes of A1h + FBh  (Chapter I - section 7) when

attempting to read a sector.

An example is given in Chapter V - section 4.




5. POSITIONING THE READ/WRITE HEAD ON THE BEGINNING OF A TRACK


   In this section we shall answer question (b) raised in Chapter III-

section 6.


The trick is as follows :


We instruct the disk controller to perform a 'wrong' read track

operation; 'wrong' means that we make the disk controller to think the

recording method is an old one (not used any more). It tries to read

bytes starting at the beginning of the track. After one complete

revolution it will stop searching. That is the right time to take over

(as the read/write head is again at the beginning of the track).

As it would be a waste of time we must find a way around the necessity

to read the result phase bytes. The only reasonable way is to perform

a disk controller reset. That can be done by resetting bits of the DOR

register (Chapter III - section 3) :



reset         proc      near

              mov       dx,3f2h

              mov       cl,drive

              mov       al,10h

              shl       al,cl

              or        al,cl

              or        al,8

              out       dx,al

              or        al,4

              jmp       rs1

rs1:          out       dx,al

              ret

reset         endp



Now, the 'wrong' read track operation is quite similar to the standard

one. We only need to change the first byte in the command phase

sequence to  02   and set the number of bytes to be read (DMA

parameter) to  8 .


We conclude by putting things together :


      (A) Turn the disk motor on               (if necessary)

      (B) Recalibrate the read/write head      (if necessary)

      (C) Position the read/write head over the desired track

                                               (if necessary)

      (D) Initialize the DMA

      (E) Command phase

      (F) Wait for the transfer to be 'complete', i.e. allow the disk

               controller to realize nothing can be read

               (wait_int procedure in section 3)

      (G) Perform a disk controller reset

      (H) Carry on IMMEDIATELY

          e.g. read CHRN fields in a loop






                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                  ³

                        ³    CHAPTER  V    ³

                        ³                  ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



                 ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                 ³                                ³

                 ³    THE LDC FORMAT OPERATION    ³

                 ³                                ³

                 ³    AND OTHER LDC OPERATIONS    ³

                 ³                                ³

                 ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




1. THE COMPLETE LDC FORMAT OPERATION


   Although there is no point in performing complete LDC format

operations (because that is just what INT 13h/function 5 does),some

almost trivial modification will allow us to perform what we are

really interested in : ABORTED format operations.


The complete technique involves the following steps :


         (A) Turn the disk drive motor on         (if necessary)

         (B) Recalibrate the read/write head      (if necessary)

         (C) Position the read/write head over the desired track

                                                  (if necessary)

         (D) Initialize the DMA                      (see below)

         (E) Command phase                           (see below)

         (F) Wait for the operation to be complete

             (wait_int procedure; see Chapter IV - section 3)


         (G) Read the result phase bytes             (see below)



The DMA initialization step is quite standard (see Chapter IV -

section 2); the DMA command code is of course  4Ah  (write) and the

number of bytes to transfer is  4 * (number of sectors per track).


The command phase requires a 6-byte sequence as follows :


          ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

          ³                                                 ³

          ³       format track command phase sequence       ³

          ³                                                 ³

          ÃÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³ byte  ³                                         ³

          ³  no   ³              description                ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  01   ³  MUST be  4Dh                           ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  02   ³  (4 * head) + drive                     ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  03   ³  data size code                         ³

          ³       ³  code n means  128 * 2^n bytes/sector   ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  04   ³  number of sectors/track                ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  05   ³  format gap length                      ³

          ³       ³   (number of bytes of  4Eh  written     ³

          ³       ³   between sectors)                      ³

          ³       ³                                         ³

          ÃÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

          ³       ³                                         ³

          ³  06   ³  format fill byte                       ³

          ³       ³   (the data value stored in each byte   ³

          ³       ³   of the sectors when a track is        ³

          ³       ³   formatted)                            ³

          ³       ³                                         ³

          ÀÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





The result phase provides 7 bytes. Details are given in Hogan's

Sourcebook (8.19). The result bytes MUST be read (unless a disk

controller reset is performed).




2. ABORTED FORMAT OPERATIONS


   A format operation may be aborted any time. All that is needed is

to perform a disk controller reset (see chapter IV - section 5).

The abortion is usually performed in the following circumstances :


   . While the CRC bytes for the last CHRN field are being written.

     This is the only way to 'write' a bad CRC word for a CHRN field.

     Such sectors are called 'hidden sectors' because they are not

     spotted by the standard method described in Chapter III. We shall

     discuss hidden sectors in section 4.


   . Just after the CRC bytes for the last CHRN field are written.

     This is the way to ensure that a sector has no data marks

     (3 bytes of A1h + FBh); see Chapter I - section 7.


   . While the data bytes are being written or while the CRC bytes for

     the data field are being written. These are ways to 'write' a bad

     CRC word for a data field.


   . Just after the last sector is written (see example 1 below).


To play such tricks we need to know when the last CHRN field is about

to be written. That is when the DMA counter (accessible through

port 5) holds a value of  FFFFh .


The following procedure may be used :



; abort       the wait_int procedure may NOT be used when

;             dealing with aborted operations because  it

;             waits for the operation to be complete!



abort         proc      near

              mov       dh,2       ; or any suitable value

              xor       cx,cx

ab1:          in        al,5

              mov       ah,al

              in        al,5

              cmp       ax,0ffffh

              je        ab2

              loop      ab1

              dec       dh

              jnz       ab1

              jmp       ab_error


ab2:


;

;             delay  (depending on one wants to do)

;

;             perform a disk controller reset

;

              ret


ab_error:


;

;             time out error

;

;             tell the calling program

;


abort         endp




WARINING: Issuing an aborted format command may occasionally cause a

          'glitch' on the opposite side of the diskette (same track).

This is probably due to a hardware bug.



   Let us denote


   the number of sectors/track (command phase parameter)  by  EOT

   the sector size code (command phase parameter)         by  NN

   the format gap length (command phase parameter)        by  FGL


We are now ready to give a few examples.



EXAMPLE 1


We want track 21/head 0 to contain 12 sectors as follows:


   CHRN field  ³ CHRN ³ true data ³ data ³

               ³ CRC  ³   size    ³ CRC  ³          remarks

  ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   21 00 01 02 ³  ok  ³    512    ³  ok  ³

   21 00 02 02 ³  ok  ³    512    ³  ok  ³

   21 00 03 02 ³  ok  ³    512    ³  ok  ³

   21 00 04 02 ³  ok  ³    512    ³  ok  ³

   21 00 05 02 ³  ok  ³    512    ³  ok  ³

   21 00 06 02 ³  ok  ³    512    ³  ok  ³

   21 00 07 02 ³  ok  ³    512    ³  ok  ³

   21 00 08 02 ³  ok  ³    512    ³  ok  ³

   21 00 09 02 ³  ok  ³    512    ³  ok  ³

   21 00 10 01 ³  ok  ³    256    ³  ok  ³

   21 33 12 02 ³  bad ³    ---    ³  --  ³ no data; just hidden sect


Two passes are required to format such a track.


(a) Call format with     EOT =  12        track = 21

                         FGL = 233        head  =  0

                         NN  =   1


                         CHRN fields      21 00 01 02

                                          21 00 02 02

                                          21 00 03 02

                                          21 00 04 02

                                          21 00 05 02

                                          21 00 06 02

                                          21 00 07 02

                                          21 00 08 02

                                          21 00 09 02

                                          21 00 10 01

                                          21 33 12 02


                         ABORT while CRC bytes for last CHRN field.

                               are being written


(b) Call format with     EOT =  9         track = 21

                         FGL = 32         head  =  0

                         NN  =  2


                         CHRN fields      21 00 01 02

                                          21 00 02 02

                                          21 00 03 02

                                          21 00 04 02

                                          21 00 05 02

                                          21 00 06 02

                                          21 00 07 02

                                          21 00 08 02

                                          21 00 09 02


                         ABORT just after the last sector is written.


Some elementary arithmetic is necessary to determine the FGL values.

The table in Appendix B may be helpful.



EXAMPLE 2


We want track 22/head 0 to contain 9 sectors as follows:


   CHRN field  ³ CHRN ³ true data ³ data ³

               ³ CRC  ³   size    ³ CRC  ³          remarks

  ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   22 00 01 02 ³  ok  ³    512    ³  ok  ³ wrong angular position (*)

   22 00 02 02 ³  ok  ³    512    ³  ok  ³

   22 00 03 02 ³  ok  ³    512    ³  ok  ³

   22 00 04 02 ³  ok  ³    512    ³  ok  ³

   22 00 05 02 ³  ok  ³    512    ³  ok  ³

   22 00 06 02 ³  ok  ³    512    ³  ok  ³

   22 00 07 02 ³  ok  ³    512    ³  ok  ³

   22 00 08 02 ³  ok  ³    512    ³  ok  ³

   22 00 09 02 ³  ok  ³    512    ³  bad ³


   (*) we want the angular position of the first CHRN field to be 25ø



Call format with         EOT = 19         track = 22

                         FGL = 80         head  =  0

                         NN  =  2


                         CHRN fields      22 00 01 02

                                          22 00 02 02

                                          22 00 03 02

                                          22 00 04 02

                                          22 00 05 02

                                          22 00 06 02

                                          22 00 07 02

                                          22 00 08 02

                                          22 00 09 02

                                          22 00 10 02

                                          22 00 01 02

                                          22 00 02 02

                                          22 00 03 02

                                          22 00 04 02

                                          22 00 05 02

                                          22 00 06 02

                                          22 00 07 02

                                          22 00 08 02

                                          22 00 09 02


                         ABORT while the CRC bytes for the last sector

                               data bytes are being written.


This trick is used by some copy protection methods.

Note that some of the data bytes for sector 9 are at the beginning of

the track while the other ones are at the end of the track.

The data CRC error in sector 9 will be corrected if this sector is

rewritten (unless an aborted write operation is performed).



EXAMPLE 3


This example demonstrates an overwriting technique that is often

quite useful.

We want track 23/head 0 to contain 7 sectors as follows:


   CHRN field  ³ CHRN ³ true data ³ data ³

               ³ CRC  ³   size    ³ CRC  ³          remarks

  ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   23 00 01 01 ³  ok  ³    256    ³  ok  ³

   23 00 02 02 ³  ok  ³    512    ³  ok  ³

   23 00 03 03 ³  ok  ³   1024    ³  ok  ³

   23 00 04 03 ³  ok  ³   1024    ³  ok  ³

   23 00 05 03 ³  ok  ³   1024    ³  ok  ³

   23 00 06 02 ³  ok  ³    512    ³  ok  ³

   23 00 07 04 ³  ok  ³    ---    ³  --  ³ no data; CHRN field only



Call format with         EOT = 15         track = 23

                         FGL = 85         head  =  0

                         NN  =  1


                         CHRN fields      23 00 01 01

                                          23 00 02 02

                                          23 00 21 01

                                          23 00 03 03

                                          23 00 31 01

                                          23 00 32 01

                                          23 00 04 03

                                          23 00 41 01

                                          23 00 42 01

                                          23 00 05 03

                                          23 00 51 01

                                          23 00 52 01

                                          23 00 06 02

                                          23 00 61 01

                                          23 00 07 04


                         ABORT just after CRC bytes for the last

                               CHRN field are written.


Writing the appropriate number of bytes to sectors 1..6 will destroy

the unwanted CHRN fields (INT 13h/function 3 may be used).



EXERCISE


Format track track 24/head 0 as follows:


   CHRN field  ³ CHRN ³ true data ³ data ³

               ³ CRC  ³   size    ³ CRC  ³          remarks

  ÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

   24 00 01 02 ³  ok  ³    512    ³  ok  ³

   24 00 02 02 ³  ok  ³    512    ³  ok  ³

   24 00 03 02 ³  ok  ³    512    ³  ok  ³

   24 00 04 02 ³  ok  ³    512    ³  ok  ³

   24 00 05 02 ³  ok  ³    512    ³  ok  ³

   24 00 06 02 ³  ok  ³    512    ³  ok  ³

   24 00 07 02 ³  ok  ³    512    ³  ok  ³

   24 00 08 02 ³  ok  ³    512    ³  ok  ³

   24 00 09 02 ³  ok  ³    ---    ³  --  ³ no data; CHRN field only.

   24 00 10 02 ³  ok  ³    512    ³  ok  ³ CHRN fields for sectors

               ³      ³           ³      ³ 9 and 10 must be 7ø apart




3. OTHER LDC OPERATIONS


   The disk controller accepts some other useful operations :


      . Read data

      . Write data

      . Read deleted data

      . Write deleted data


From a programming point of view these operations are quite similar

to the read track operation (Chapter IV). Details may be found in

Hogan's Sourcebook (8.18).

They may be aborted (using the same technique as described for

format).


Just a few words about 'deleted' data. The terminology is misleading.

Deleted data are not physically erased! They are just marked as

deleted (i.e. the normal data mark  3 bytes of A1h + FBh  is changed

into  3 bytes of A1h + FAh . That is the secret!).



EXERCISE


Disassemble the INT 13h ROM routines.

It is not a trivial exercise but it is quite rewarding.





4. HIDDEN SECTORS


   First we want to know how read track deals with hidden sectors.

Let us carry out the following experiment:


(a) We need a brand new diskette (because we do not want leftovers

    from previous format operations).


    Call format with     EOT =  9         track = 21

                         FGL = 80         head  =  0

                         NN  =  2


                         CHRN fields      21 00 01 02

                                          21 00 02 02

                                          21 00 03 02

                                          21 00 04 02

                                          21 00 05 02

                                          21 00 06 02

                                          21 00 07 02

                                          21 00 08 02

                                          21 00 09 02


                         ABORT while the CRC bytes for the last

                               CHRN field are being written



Next call format with    EOT =  1         track = 21

                         FGL = 80         head  =  0

                         NN  =  2


                         CHRN field       27 12 13 14


                         ABORT while the CRC bytes for the

                               CHRN field are being written



Track 21/head 0 now contains two hidden sectors.



(b) Call read track with   NB  = 1200h       track = 21

                           EOT = 9           head  = 0

                           NN  = 2

                           GL  = 2Ah


The result phase bytes show CRC errors and a missing address mark

error. The data buffer contains the data bytes form sectors 1..8.



Next call read track with  NB  = 2400h       track = 21

                           EOT = 9           head  = 0

                           NN  = 3

                           GL  = 2Ah


The result phase bytes show CRC errors and a missing address mark

error. 1000h bytes are transferred to the data buffer.



CONCLUSION : Read track does not mind CHRN fields with bad CRC but it

             aborts when it does not find a data mark.



REMARK : There is a way around the brand new disk requirement

         mentioned above. Reformatting a track with one sector of

size code 6 does not leave any CHRN field or data mark.




We now discuss a difficult problem : finding hidden sectors.

The technique described in Chapter III does not report the CHRN fields

with bad CRC.

Read track may sometimes help to report the existence of a hidden

sector but it does not generally allows to identify such a sector.

The read command is useful to confirm the existence of a hidden sector

(if we know its CHRN field) because the result phase bytes show

a CRC error for the CHRN field.


I confess I do not know of a general method to spot all hidden sectors

on a track.

I shall describe what I know about it. Comments from readers will be

most welcome.


Suppose that  c h r n   ,  c' h' r' n'  are the nth and the (n+1)th

visible CHRN fields. We discuss a method to spot an in between hidden

sector provided :


           . the CHRN fields are not too close to each other

           . the hidden sector CHRN field is not of  c h r n


 (i)  Position the read/write head on the beginning of the track (using

      the technique described in Chapter IV - section 5)


(ii)  Position the read/write head a few bytes further than the  nth

      CHRN field (by reading  n  CHRN fields)


(iii) Issue a read CHRN command. This operation MUST be aborted so

      that the disk controller is not given any chance to read the

      (n+1)th  CHRN field. The timing is of course critical!


(iv)  The previous step being an aborted operation we do not know

      about the result phase bytes. They are kept secret by the disk

      controller. So we want it to confide its secret.

      The trick is to issue a 'wrong' read CHRN command (change the

      first byte in the command phase sequence to  OAh ). The four

      last result phase bytes provide us with a CHRN field. If it is

      not of  c h r n  then we have found a hidden sector (if it is

      of  c' h' r' n'  we could retry with a shorter delay in

      step (iii), just to be sure).





REMARK : Searching for all hidden sectors on a track can take a 'long'

         time. So it is good practice to revitalize the motor shut off

count down byte at memory location  0000:0440h.

This is quite easy :



revital         proc      near

                xor       ax,ax

                mov       es,ax

                cli

                or        es:[0440h],0ffh

                sti

                ret

revital         endp




Turning the motor off when disk accesses are no longer needed can be

done in a similar way : setting the motor shut off count down byte to

a small value (say 25h) is a good way to do it.







                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                  ³

                        ³    APPENDIX  A   ³

                        ³                  ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³           CYCLIC REDUNDANCY CODES           ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




1. GENERALITIES


   Coding theory is concerned with the transmission of information.

During transmission a message may be slightly changed (due to a

'noisy' channel). Building some appropriately chosen redundancy in

the message is a standard way to allow the receiver to detect some

transmission errors.

For example, to transmit a 'true' 200-byte message one can send

202 bytes, the two final bytes being used as a word whose value is

the sum of the 'true' message bytes.

We will not discuss general coding theory. Only one very special case

will be covered. Sorry, ... Some algebra is involved.


Let us denote the 2-element set  [0,1]  by  F[2]  (this is no standard

mathematical notation ; it is just easier to type in).


We need new addition and substraction operations for  F[2] (we want

a + b  and  a - b  to be in  F[2]  when  a  and  b  are).


We define a new  +  operation by the following table :



                    +  ³   0     1

                   ÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄ

                    0  ³   0     1

                       ³

                    1  ³   1     0


Note that this is just the truth-table for  XOR .


Now, the only reasonable way to define a new  -  (minus) operation is


          a - b  =  a  +  b     (for all a, b  in  F[2] ).


This is not an error; we really mean it!


What about multiplication ?

That is not difficult : we keep the standard one. Another way to put

it : the multiplication table is just the truth-table for  AND .

So, division does not deserve any explanation.


Let us say that a polynomial is  * over *  F[2]  whenever all its

coefficients are in  F[2] .


We can work with polynomials over  F[2]  just as we have learned in

high school algebra, except that the new  +  operation should be

used whenever coefficients are to be summed.


Here are a few examples :


(x^2 + 1) (x^2 + x + 1)  =  x^4 + x^3 + x + 1  ;


(x + 1) (x^15 + x^14 + x^13 + x^12 + x^4 + x^3 + x^2 + x + 1)  =


                x^16 + x^12 + x^5 + 1  ;




Dividing  x^3 + x^2 + x    by    x + 1 , we find :



                            x^2 + 1            <---  quotient

                   ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

           x + 1   ³  x^3 + x^2 + x

                      x^3 + x^2

                    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                                  x

                                  x + 1

                    ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

                                      1        <---  remainder




The following polynomial (known as the CRC-CCITT polynomial) is very

important for diskette operations (as will appear in section 2) :



           ÚÄÄÄ  CRC-CCITT polynomial  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³            x^16 + x^12 + x^5 + 1            ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ




2. GENERATING CYCLIC REDUNDANCY CHECK WORDS


   (a) Let us assume that  array_data  is an array[0..nn - 1] of

       bytes. We want to regard  array_data  as a polynomial over

F[2].

Writing in a row the binary representation of all bytes of array_data

provides us with a sequence of  nn * 8  bits:


                 b[i]      (0  <=  i  <=  8 * nn - 1) .


Now, the polynomial we are looking for is just the sum of all

monomials

                 b[i] . x^(8 * nn - 1 - i).


Let us give an example to show all this is much simpler than it looks.

Assuming that  array_data  is a 3-byte array and that


array_data[0] = F0h    array_data[1] = 10h    array_data[2] = 21h ,


we find that the binary representation sequence is


                F0h             10h             21h

         ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

          1 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 1


and that the corresponding polynomial is


            x^23 + x^22 + x^21 + x^20 + x^12 + x^5 + 1 .



(b) Let array_data be as above. We denote the corresponding polynomial

    (as defined in (a)) by  p(x).

Let  r(x)  be the  * remainder *  of the division of


             x^16 . p(x)   by the CRC-CCITT polynomial.


The degree of r(x) is, of course, less than 16 and therefore  r(x)

corresponds to a word  w .

We call  w  the 'TCRC word for array_data' (T stands for temporary).


TCRC words may be evaluated quite easily : assembly language provides

SHL  and  XOR  instructions and nothing more is required!


Here is a skech of a TCRC program :



array_data       db ..............

size_of_array       dw ....


tcrc_word             dw ?


..............................................

..............................................



        mov cx,size_of_array

        mov ax,0                     ; (*) line marked for

                                                 ; further reference

mov bx,offset array_data

again:

xor ah,[bx]

call partial

inc bx

loop again


mov tcrc_word,ax


                ....................

                ....................



partial proc near

push cx

mov cx,8

p1: shl ax,1

jnc p2

xor ax,1021h

p2: loop p1

pop cx

ret

partial endp




(c)  The disk controller uses a variant of TCRC words : CRC words.


CRC words may be evaluated almost like TCRC words ; we only need to

change the line marked (*) in the program above into


                mov     ax,0ffffh


We also need to know that the disk controller writes and reads CRC

words in an unconventional way :


          *     Most  significant byte first    *

          *     Least significant byte last     *


We are now able to describe the bytes CRC1, CRC2, CRC3 and CRC4 in

the fine structure of a sector (Chapter I - section 7).


    (i)  CRC1 and CRC2 hold the CRC word of the 8-byte array :


                A1h  A1h  A1h  FEh  C  H  R  N     .


    (ii) CRC3 and CRC4 hold the CRC word of the

         (4 + (number of data bytes))-byte array:


                A1h  A1h  A1h  FBh   data bytes    .



That's all!









                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                  ³

                        ³    APPENDIX  B   ³

                        ³                  ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³         DISK SPACE USED BY SECTORS          ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





The fine structure of sectors (Chapter I - section 7) shows that a

sector requires


            62  +  128 * 2^N  +  size of format gap


disk bytes.


Some disk utilities display the measure (expressed in degrees) of the

arc used by a sector (about  36/625 * number of disk bytes).


The following table gives the measure of sector arcs for N in  [0..4]

and format gap in  [6..255].


The table is useful to try guessing the size of the format gap when

N and sector arc are known.


     Gap       N=0        N=1        N=2        N=3       N=4

     ---------------------------------------------------------

     06h      11.3       18.7       33.5       62.9      121.9

     07h      11.4       18.8       33.5       63.0      122.0

     08h      11.5       18.8       33.6       63.1      122.0

     09h      11.5       18.9       33.6       63.1      122.1

     0Ah      11.6       18.9       33.7       63.2      122.2

     0Bh      11.6       19.0       33.7       63.2      122.2

     0Ch      11.7       19.1       33.8       63.3      122.3

     0Dh      11.7       19.1       33.9       63.4      122.3

     0Eh      11.8       19.2       33.9       63.4      122.4

     0Fh      11.9       19.2       34.0       63.5      122.4

     10h      11.9       19.3       34.0       63.5      122.5

     11h      12.0       19.3       34.1       63.6      122.6

     12h      12.0       19.4       34.1       63.6      122.6

     13h      12.1       19.5       34.2       63.7      122.7

     14h      12.1       19.5       34.3       63.8      122.7

     15h      12.2       19.6       34.3       63.8      122.8      

     16h      12.3       19.6       34.4       63.9      122.9      

     17h      12.3       19.7       34.4       63.9      122.9      

     18h      12.4       19.7       34.5       64.0      123.0

     19h      12.4       19.8       34.6       64.0      123.0      

     1Ah      12.5       19.9       34.6       64.1      123.1      

     1Bh      12.5       19.9       34.7       64.2      123.1      

     1Ch      12.6       20.0       34.7       64.2      123.2      

     1Dh      12.7       20.0       34.8       64.3      123.3      

     1Eh      12.7       20.1       34.8       64.3      123.3      

     1Fh      12.8       20.2       34.9       64.4      123.4      

     20h      12.8       20.2       35.0       64.4      123.4      

     21h      12.9       20.3       35.0       64.5      123.5      

     22h      13.0       20.3       35.1       64.6      123.5      

     23h      13.0       20.4       35.1       64.6      123.6      

     24h      13.1       20.4       35.2       64.7      123.7      

     25h      13.1       20.5       35.2       64.7      123.7      

     26h      13.2       20.6       35.3       64.8      123.8      

     27h      13.2       20.6       35.4       64.8      123.8      

     28h      13.3       20.7       35.4       64.9      123.9      

     29h      13.4       20.7       35.5       65.0      123.9      

     2Ah      13.4       20.8       35.5       65.0      124.0      

     2Bh      13.5       20.8       35.6       65.1      124.1      

     2Ch      13.5       20.9       35.6       65.1      124.1      

     2Dh      13.6       21.0       35.7       65.2      124.2

     2Eh      13.6       21.0       35.8       65.3      124.2      

     2Fh      13.7       21.1       35.8       65.3      124.3      

     30h      13.8       21.1       35.9       65.4      124.4      

     31h      13.8       21.2       35.9       65.4      124.4      

     32h      13.9       21.2       36.0       65.5      124.5      

     33h      13.9       21.3       36.0       65.5      124.5      

     34h      14.0       21.4       36.1       65.6      124.6      

     35h      14.0       21.4       36.2       65.7      124.6      

     36h      14.1       21.5       36.2       65.7      124.7      

     37h      14.2       21.5       36.3       65.8      124.8      

     Gap       N=0        N=1        N=2        N=3       N=4

     ---------------------------------------------------------

     38h      14.2       21.6       36.3       65.8      124.8      

     39h      14.3       21.6       36.4       65.9      124.9      

     3Ah      14.3       21.7       36.5       65.9      124.9      

     3Bh      14.4       21.8       36.5       66.0      125.0      

     3Ch      14.4       21.8       36.6       66.1      125.0      

     3Dh      14.5       21.9       36.6       66.1      125.1      

     3Eh      14.6       21.9       36.7       66.2      125.2      

     3Fh      14.6       22.0       36.7       66.2      125.2

     40h      14.7       22.1       36.8       66.3      125.3      

     41h      14.7       22.1       36.9       66.3      125.3      

     42h      14.8       22.2       36.9       66.4      125.4      

     43h      14.9       22.2       37.0       66.5      125.4      

     44h      14.9       22.3       37.0       66.5      125.5      

     45h      15.0       22.3       37.1       66.6      125.6      

     46h      15.0       22.4       37.1       66.6      125.6      

     47h      15.1       22.5       37.2       66.7      125.7      

     48h      15.1       22.5       37.3       66.8      125.7      

     49h      15.2       22.6       37.3       66.8      125.8      

     4Ah      15.3       22.6       37.4       66.9      125.8      

     4Bh      15.3       22.7       37.4       66.9      125.9      

     4Ch      15.4       22.7       37.5       67.0      126.0      

     4Dh      15.4       22.8       37.5       67.0      126.0      

     4Eh      15.5       22.9       37.6       67.1      126.1      

     4Fh      15.5       22.9       37.7       67.2      126.1      

     50h      15.6       23.0       37.7       67.2      126.2      

     51h      15.7       23.0       37.8       67.3      126.3      

     52h      15.7       23.1       37.8       67.3      126.3      

     53h      15.8       23.1       37.9       67.4      126.4      

     54h      15.8       23.2       38.0       67.4      126.4

     55h      15.9       23.3       38.0       67.5      126.5      

     56h      15.9       23.3       38.1       67.6      126.5      

     57h      16.0       23.4       38.1       67.6      126.6      

     58h      16.1       23.4       38.2       67.7      126.7      

     59h      16.1       23.5       38.2       67.7      126.7      

     5Ah      16.2       23.6       38.3       67.8      126.8      

     5Bh      16.2       23.6       38.4       67.8      126.8      

     5Ch      16.3       23.7       38.4       67.9      126.9      

     5Dh      16.4       23.7       38.5       68.0      126.9      

     5Eh      16.4       23.8       38.5       68.0      127.0      

     5Fh      16.5       23.8       38.6       68.1      127.1      

     60h      16.5       23.9       38.6       68.1      127.1      

     61h      16.6       24.0       38.7       68.2      127.2      

     62h      16.6       24.0       38.8       68.2      127.2      

     63h      16.7       24.1       38.8       68.3      127.3      

     64h      16.8       24.1       38.9       68.4      127.3      

     65h      16.8       24.2       38.9       68.4      127.4      

     66h      16.9       24.2       39.0       68.5      127.5      

     67h      16.9       24.3       39.0       68.5      127.5      

     68h      17.0       24.4       39.1       68.6      127.6      

     69h      17.0       24.4       39.2       68.7      127.6

     Gap       N=0        N=1        N=2        N=3       N=4

     ---------------------------------------------------------

     6Ah      17.1       24.5       39.2       68.7      127.7      

     6Bh      17.2       24.5       39.3       68.8      127.7      

     6Ch      17.2       24.6       39.3       68.8      127.8      

     6Dh      17.3       24.6       39.4       68.9      127.9      

     6Eh      17.3       24.7       39.4       68.9      127.9      

     6Fh      17.4       24.8       39.5       69.0      128.0      

     70h      17.4       24.8       39.6       69.1      128.0      

     71h      17.5       24.9       39.6       69.1      128.1      

     72h      17.6       24.9       39.7       69.2      128.2      

     73h      17.6       25.0       39.7       69.2      128.2      

     74h      17.7       25.0       39.8       69.3      128.3      

     75h      17.7       25.1       39.9       69.3      128.3      

     76h      17.8       25.2       39.9       69.4      128.4      

     77h      17.8       25.2       40.0       69.5      128.4      

     78h      17.9       25.3       40.0       69.5      128.5      

     79h      18.0       25.3       40.1       69.6      128.6      

     7Ah      18.0       25.4       40.1       69.6      128.6      

     7Bh      18.1       25.5       40.2       69.7      128.7

     7Ch      18.1       25.5       40.3       69.7      128.7      

     7Dh      18.2       25.6       40.3       69.8      128.8      

     7Eh      18.3       25.6       40.4       69.9      128.8      

     7Fh      18.3       25.7       40.4       69.9      128.9      

     80h      18.4       25.7       40.5       70.0      129.0      

     81h      18.4       25.8       40.5       70.0      129.0      

     82h      18.5       25.9       40.6       70.1      129.1      

     83h      18.5       25.9       40.7       70.1      129.1      

     84h      18.6       26.0       40.7       70.2      129.2      

     85h      18.7       26.0       40.8       70.3      129.2      

     86h      18.7       26.1       40.8       70.3      129.3      

     87h      18.8       26.1       40.9       70.4      129.4      

     88h      18.8       26.2       40.9       70.4      129.4      

     89h      18.9       26.3       41.0       70.5      129.5      

     8Ah      18.9       26.3       41.1       70.6      129.5      

     8Bh      19.0       26.4       41.1       70.6      129.6      

     8Ch      19.1       26.4       41.2       70.7      129.6      

     8Dh      19.1       26.5       41.2       70.7      129.7      

     8Eh      19.2       26.5       41.3       70.8      129.8      

     8Fh      19.2       26.6       41.3       70.8      129.8      

     90h      19.3       26.7       41.4       70.9      129.9

     91h      19.3       26.7       41.5       71.0      129.9      

     92h      19.4       26.8       41.5       71.0      130.0      

     93h      19.5       26.8       41.6       71.1      130.1      

     94h      19.5       26.9       41.6       71.1      130.1      

     95h      19.6       26.9       41.7       71.2      130.2      

     96h      19.6       27.0       41.8       71.2      130.2      

     97h      19.7       27.1       41.8       71.3      130.3      

     98h      19.7       27.1       41.9       71.4      130.3      

     99h      19.8       27.2       41.9       71.4      130.4      

     9Ah      19.9       27.2       42.0       71.5      130.5      

     9Bh      19.9       27.3       42.0       71.5      130.5      

     Gap       N=0        N=1        N=2        N=3       N=4

     ---------------------------------------------------------

     9Ch      20.0       27.4       42.1       71.6      130.6      

     9Dh      20.0       27.4       42.2       71.6      130.6      

     9Eh      20.1       27.5       42.2       71.7      130.7      

     9Fh      20.2       27.5       42.3       71.8      130.7      

     A0h      20.2       27.6       42.3       71.8      130.8      

     A1h      20.3       27.6       42.4       71.9      130.9      

     A2h      20.3       27.7       42.4       71.9      130.9

     A3h      20.4       27.8       42.5       72.0      131.0      

     A4h      20.4       27.8       42.6       72.0      131.0      

     A5h      20.5       27.9       42.6       72.1      131.1      

     A6h      20.6       27.9       42.7       72.2      131.1      

     A7h      20.6       28.0       42.7       72.2      131.2      

     A8h      20.7       28.0       42.8       72.3      131.3      

     A9h      20.7       28.1       42.8       72.3      131.3      

     AAh      20.8       28.2       42.9       72.4      131.4      

     ABh      20.8       28.2       43.0       72.5      131.4      

     ACh      20.9       28.3       43.0       72.5      131.5      

     ADh      21.0       28.3       43.1       72.6      131.6      

     AEh      21.0       28.4       43.1       72.6      131.6      

     AFh      21.1       28.4       43.2       72.7      131.7      

     B0h      21.1       28.5       43.2       72.7      131.7      

     B1h      21.2       28.6       43.3       72.8      131.8      

     B2h      21.2       28.6       43.4       72.9      131.8      

     B3h      21.3       28.7       43.4       72.9      131.9      

     B4h      21.4       28.7       43.5       73.0      132.0      

     B5h      21.4       28.8       43.5       73.0      132.0      

     B6h      21.5       28.8       43.6       73.1      132.1      

     B7h      21.5       28.9       43.7       73.1      132.1

     B8h      21.6       29.0       43.7       73.2      132.2      

     B9h      21.6       29.0       43.8       73.3      132.2      

     BAh      21.7       29.1       43.8       73.3      132.3      

     BBh      21.8       29.1       43.9       73.4      132.4      

     BCh      21.8       29.2       43.9       73.4      132.4      

     BDh      21.9       29.3       44.0       73.5      132.5      

     BEh      21.9       29.3       44.1       73.5      132.5      

     BFh      22.0       29.4       44.1       73.6      132.6      

     C0h      22.1       29.4       44.2       73.7      132.6      

     C1h      22.1       29.5       44.2       73.7      132.7      

     C2h      22.2       29.5       44.3       73.8      132.8      

     C3h      22.2       29.6       44.3       73.8      132.8      

     C4h      22.3       29.7       44.4       73.9      132.9      

     C5h      22.3       29.7       44.5       74.0      132.9      

     C6h      22.4       29.8       44.5       74.0      133.0      

     C7h      22.5       29.8       44.6       74.1      133.0      

     C8h      22.5       29.9       44.6       74.1      133.1      

     C9h      22.6       29.9       44.7       74.2      133.2      

     CAh      22.6       30.0       44.7       74.2      133.2      

     CBh      22.7       30.1       44.8       74.3      133.3      

     CCh      22.7       30.1       44.9       74.4      133.3

     CDh      22.8       30.2       44.9       74.4      133.4      

     Gap       N=0        N=1        N=2        N=3       N=4

     ---------------------------------------------------------

     CEh      22.9       30.2       45.0       74.5      133.5      

     CFh      22.9       30.3       45.0       74.5      133.5      

     D0h      23.0       30.3       45.1       74.6      133.6      

     D1h      23.0       30.4       45.2       74.6      133.6      

     D2h      23.1       30.5       45.2       74.7      133.7      

     D3h      23.1       30.5       45.3       74.8      133.7      

     D4h      23.2       30.6       45.3       74.8      133.8      

     D5h      23.3       30.6       45.4       74.9      133.9      

     D6h      23.3       30.7       45.4       74.9      133.9      

     D7h      23.4       30.8       45.5       75.0      134.0      

     D8h      23.4       30.8       45.6       75.0      134.0      

     D9h      23.5       30.9       45.6       75.1      134.1      

     DAh      23.6       30.9       45.7       75.2      134.1      

     DBh      23.6       31.0       45.7       75.2      134.2      

     DCh      23.7       31.0       45.8       75.3      134.3      

     DDh      23.7       31.1       45.8       75.3      134.3      

     DEh      23.8       31.2       45.9       75.4      134.4

     DFh      23.8       31.2       46.0       75.4      134.4      

     E0h      23.9       31.3       46.0       75.5      134.5      

     E1h      24.0       31.3       46.1       75.6      134.5      

     E2h      24.0       31.4       46.1       75.6      134.6      

     E3h      24.1       31.4       46.2       75.7      134.7      

     E4h      24.1       31.5       46.2       75.7      134.7      

     E5h      24.2       31.6       46.3       75.8      134.8      

     E6h      24.2       31.6       46.4       75.9      134.8      

     E7h      24.3       31.7       46.4       75.9      134.9      

     E8h      24.4       31.7       46.5       76.0      134.9      

     E9h      24.4       31.8       46.5       76.0      135.0      

     EAh      24.5       31.8       46.6       76.1      135.1      

     EBh      24.5       31.9       46.6       76.1      135.1      

     ECh      24.6       32.0       46.7       76.2      135.2      

     EDh      24.6       32.0       46.8       76.3      135.2      

     EEh      24.7       32.1       46.8       76.3      135.3      

     EFh      24.8       32.1       46.9       76.4      135.4      

     F0h      24.8       32.2       46.9       76.4      135.4      

     F1h      24.9       32.2       47.0       76.5      135.5      

     F2h      24.9       32.3       47.1       76.5      135.5      

     F3h      25.0       32.4       47.1       76.6      135.6

     F4h      25.0       32.4       47.2       76.7      135.6      

     F5h      25.1       32.5       47.2       76.7      135.7      

     F6h      25.2       32.5       47.3       76.8      135.8      

     F7h      25.2       32.6       47.3       76.8      135.8      

     F8h      25.3       32.7       47.4       76.9      135.9      

     F9h      25.3       32.7       47.5       76.9      135.9      

     FAh      25.4       32.8       47.5       77.0      136.0      

     FBh      25.5       32.8       47.6       77.1      136.0      

     FCh      25.5       32.9       47.6       77.1      136.1      

     FDh      25.6       32.9       47.7       77.2      136.2      

     FEh      25.6       33.0       47.7       77.2      136.2      

     FFh      25.7       33.1       47.8       77.3      136.3      







                        ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

                        ³                  ³

                        ³    APPENDIX  C   ³

                        ³                  ³

                        ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



           ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

           ³                                             ³

           ³          THE STRANGE CASE OF N = 0          ³

           ³                                             ³

           ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ





The data length code N = 0  is known as the 'sector length not

specified code'.

The Disk Base Table (Chapter II - section 7) has an entry (known as)

DTL  that is supposed to hold the data length to be used when N = 0.

Such a parameter is also required in the command phase of some

LDC operations (e.g. read track).


At first glance, it does not seem too difficult to guess the meaning

of all this.


When it comes to experimenting, things turn out to be rather

surprising. To be more precise let me say that I find strange results

when experimenting. Maybe this is specific to my computer brand and /

or model.


Anyway, I think that the reader should experiment :



EXPERIMENT


(a)  Format track 10 / head 0 using INT 13h / function 5. Call with


             data length code    00

             sectors / track     09

             format gap          80

             fill byte           F6h

             CHRN fields         10  0  R  0   (1  <=  R  <=  9).


The DTL value is irrelevant to format operations; if the data length

code is 0, the data length is always 128.



(b)  Reformat (a part of) track 10 / head 0  using an ABORTED  LDC

     format operation. Call with


             data length code    00

             sectors / track     01

             fill byte           F5h

             CHRN field          10  0  1  0 .


The operation MUST be ABORTED immediately after the data field CRC

word is written to the disk.



(c)  Use a LDC read track operation (call with  N = 0) to read

     track 10 / head 0.

When I do this I find


                        80 bytes of F5h

       followed by      bytes of F6h


(whatever the value of DTL is) !


No CRC error is reported.



(d)  Use INT 13h / function 2  to read track 10 / head 0 / sector 1.

     When I do this I find


                        80 bytes of F5h

       followed by      48 bytes of F6h    (from sector 2 )


(whatever the value of DTL is) !


No CRC error is reported.




My conclusion is (maybe it only applies to my computer) that

with  N = 0 :

When it comes to  read/read track  operations the disk controller

does not look at the value of DTL ; it uses invariably a value of its

own : 80 = 50h.

No CRC error is returned because although only 80 bytes are sent to

the data bus, the disk controller reads  * internally *  the complete

sector (128 bytes) and then performs a CRC check.




What about write operations called with N = 0 ?

From my own experience they seem to be quite unreliable.




Of course, my computer capabilities are not of general interest but it

seems that readers should be warned :



    ÚÄÄÄÄ  Warning  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

    ³                                                          ³

    ³   DO NOT take it for granted that the disk controller    ³

    ³   supports sector sizes with N = 0.                      ³

    ³   Format operations cause no problem but                 ³

    ³   read/write  operations may show  'no error' although   ³

    ³   they do not read/write  WHERE  they are expected.      ³

    ³                                                          ³

    ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ



There are some 'safe' methods to try reading/writing sectors of data

length code N = 0  (they can also be used when the CHRN field shows a

value of N that does not match the 'real' data size) :


(i)   to read :  use a read track operation (call with an appropriate

                 read/write gap  and  N <> 0 ).


(ii)  writing  is more difficult; it often involves several format/

               write operations some of which are to be aborted.







Comments

Popular posts from this blog

BOTTOM LIVE script

Evidence supporting quantum information processing in animals

The Scarlet Woman