{     TITLE:  Absolete read program
   PRODUCT:  Turbo Pascal
        OS:  PC-DOS
      DATE:  1/14/85
WRITTEN BY:  Borland International
}
 {----------------------------------------------------------------------------
     This program does an absolute disk read from the drive specified.
  ---------------------------------------------------------------------------}

PROGRAM AbsoluteReadInterrupt;

TYPE
  DTAtype   = array [0..$FFF] of byte;
  str80     = string[80];
  chararr15 = array [0..15] of char;

CONST
  HexStr    : CharArr15 = '0123456789ABCDEF';

VAR
  DTA            : DTAtype;                    { Define the DTA             }
  numsect        : byte;                       { Number of sectors to read  }
  flags          : integer absolute CSEG : $00A0; { Address of the flags    }
  LogicalSector  : integer;                    { Sector to read             }
  DriveLetter    : char;                       { Drive to read from         }
  Drive          : byte;                       { Numerical value of drive   }

PROCEDURE WhichSector;                         { Get the sector to read     }

  VAR
    SectorNumber : 1..8;               { Sector within track                }
    Track        : 0..39;              { Track to read from                 }
    Side         : 0..1;               { Side to read from                  }

  BEGIN
    writeln('Side              : ');   { \                                  }
    writeln('Track             : ');   {   Write the prompts                }
    writeln('Sector            : ');   { /                                  }
    writeln('Number of Sectors : ');   {                                    }
    side := -1;
    Repeat
      GotoXY(21,2);                    { Get the side, (0 for side 1)       }
      read(side);
    Until (side in [0,1]);
    Track := -1;
    Repeat
      GotoXY(21,3);                    { Read the track number              }
      read(track);
    Until track in [0..39];
    sectornumber := -1;
    Repeat
      GotoXY(21,4);                    { Read in the relative sector number }
      read(sectornumber);
    Until sectornumber in [1..8];
    numsect := -1;
    Repeat
      GotoXY(21,5);                    { Get the number of setors to read  }
      read(numsect);
    Until (numsect in [0..64]);
                                       { Calculate the logical sector      }
    LogicalSector := (sectorNumber - 1) + (Track * 8) + (side * 320);
  END;

PROCEDURE GetSector;                   { This procedure reads the sectors  }
                                       { into the DTA                      }
  TYPE
    regpack = record                   { Define the registers              }
                ax,bx,cx,dx,bp,di,si,ds,es,flags : integer;
              end;

  VAR
    registers : regpack;

  BEGIN
    With registers do
      Begin
        ax := drive;                   { Store the drive in AX, ( 0=A,etc. }
        cx := numsect;                 { Number of sectors to read         }
        dx := LogicalSector;           { Which sector to read              }
        ds := seg(DTA);                { direct the sector data to the DTA }
        bx := ofs(DTA);                { segment and offset                }
      End;
    writeln;                           { This is the inline that saves all }
                                       { the volatile registers that INT 25}
                                       { destroys.                         }
    inline( $55             { PUSH   BP        }
           /$50             { PUSH   AX        }
           /$53             { PUSH   BX        }
           /$51             { PUSH   CX        }
           /$52             { PUSH   DX        }
           /$57             { PUSH   DI        }
           /$56             { PUSH   SI        }
           /$06             { PUSH   ES        }
           /$1E);           { PUSH   DS        }
    Intr($25,registers);               { This inline restores all the      }
                                       { registers to their origonal value }
                                       { and stores the flags in CS:00A0   }
    inline( $9F             { LAHF             }
           /$2E             { CS:              }
           /$A3 /$A0 /$00   { MOV   [00A0],AX  }
           /$9D             { POPF             }
           /$1F             { POP   DS         }
           /$07             { POP   ES         }
           /$5E             { POP   SI         }
           /$5F             { POP   DI         }
           /$5A             { POP   DX         }
           /$59             { POP   CX         }
           /$5B             { POP   BX         }
           /$58             { POP   AX         }
           /$5D);           { POP   BP         }
    If (( flags shr 8 ) and 1 ) = 1 then         { If the carry is set then  }
      Case (registers.ax shr 8 ) of               { check for errors          }
        $80: writeln('Attachment failed to respond.');
        $40: writeln('SEEK operation failed.');
        $20: writeln('Controler failure.');
        $10: writeln('Bad CRC on disk read.');
        $08: writeln('DMA overrun on operation.');
        $04: writeln('Requested sector not found.');
        $02: writeln('Address mark not found.');
        $00: writeln('Some nasty undefined error.');
      End;
  End;

FUNCTION Hex(number, len : integer):str80;  { This function converts       }
                                            { decimal to hexidecimal       }
  VAR
    buffer : str80;
    nib : byte;
    i : integer;

  BEGIN
    buffer := '';
    For i := 0 to len do
      Begin
        nib := (number shr (i * 4)) and $F;
        buffer := buffer + HexStr[ nib ];
      End;
    Hex := buffer;
  END;

PROCEDURE DumpDTA;                          { This dumps the DTA           }

  VAR
    i : integer;
  BEGIN
    For I := 0 to $FFF do
      BEGIN
      write( chr( DTA[i]));
      END;
  END;

BEGIN  { ****  Main Program  **** }
  DriveLetter := 'A';
  numsect := 1;
  write('Which drive? ');
  read(kbd, DriveLetter);
  DriveLetter := UpCase(DriveLetter);
  writeln( DriveLetter );
  If ( DriveLetter in ['A'..'D'] ) then
    Begin
      Drive := ord(DriveLetter) - 65;
      FillChar( DTA, Sizeof( DTA ), 0 );
      WhichSector;                         { Get the sector to read         }
      GetSector;                           { Read in the sector             }
      DumpDTA;                             { Dump the sector to the screen  }
    End;
END.                                                                                  