home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / utils / dskutl / swp-ms10.ark / TRAMDF.IF1 < prev    next >
Encoding:
Text File  |  1989-09-27  |  10.4 KB  |  297 lines

  1.  
  2. {* -------------------------------------------------------------------------
  3.  *   M S - D O S   S E C T O R   R E A D / W R I T E   P R O C E D U R E S
  4.  * ------------------------------------------------------------------------- *}
  5.  
  6. {*
  7.  * The procedures ReadSector and WriteSector, which read respectively write
  8.  * one sector of the MS-DOS disk, constitute the heart of TraMDF.  These
  9.  * procedures, together with procedure FlushCache, are the only procedures
  10.  * which perform MS-DOS disk I/O.
  11.  *
  12.  * Within the procedures ReadSector and WriteSector, two functions are to
  13.  * be performed.
  14.  *
  15.  * The first function to aid in mapping the sector ordinal onto the
  16.  * physical address of the sector: the cylinder ordinal, the head ordinal,
  17.  * the track number and the sector number.  For instance, sector ordinal 0
  18.  * must be mapped onto cylinder 0, head 0, track 0, sector 1.  This mapping
  19.  * is performed partly in these procedures and partly in BIOS.  These
  20.  * procedures must map the sector ordinal onto a logical track number and a
  21.  * logical record number, which in turn are mapped onto the aforementioned
  22.  * physical address by the BIOS.  The latter mapping is VERY SYSTEM DEPENDENT!
  23.  *
  24.  * In case of the ASTER CT-80, the mapping performed by BIOS is:
  25.  * - The cylinder ordinal is the logical track number divided by two.
  26.  * - The head ordinal is the remainder of this division.
  27.  * - The track number is equal to the cylinder ordinal.
  28.  * - The sector number is XLT[logical record number divided by PSS].
  29.  * One logical CP/M track is thus one physical track.  As a result, the
  30.  * mapping of the sector ordinal in procedures ReadSector and WriteSector
  31.  * is simple.
  32.  *
  33.  * Through the mapping function, any sector is addressed by a single number
  34.  * outside the procedures ReadSector and WriteSector.  The sector ordinal is
  35.  * in the range 0 (=boot-sector) through SectorsPerDisk-1.
  36.  *
  37.  * The second function is the actual disk transfer through multiple calls to
  38.  * the BIOS.  Note that there is NO call to perform sector translation.  On
  39.  * many (most?) CP/M hosts this function is a do-nothing, it is meant for
  40.  * software skewing which is not used on MS-DOS disks and, last and least,
  41.  * it requires two parameters to be passed to the BIOS, while the Bios
  42.  * procedure (function) can pass only one.
  43.  *}
  44.  
  45. procedure ReadSector( Sector, Buffer: Integer ) ;
  46. {*
  47.  * Read one MS-DOS sector from disk into the specified buffer.
  48.  *}
  49. var
  50.    CpmTrack : Integer ;  { Ordinal of logical track }
  51.    CpmRecord: Integer ;  { Ordinal of record }
  52.    BiosError: Boolean ;  { Completion status of procedure }
  53.    I        : Integer ;  { Loop control variable }
  54. begin
  55.    CpmTrack := (Sector div SectorsPerTrack) ;
  56.    CpmRecord:= (Sector mod SectorsPerTrack) * RecordsPerSector ;
  57.  
  58.    BiosError:= False ;
  59.    Bios( SelectDrive, MsdosDrive ) ;
  60.    Bios( SelectTrack, CpmTrack   ) ;
  61.    for I:= 1 to RecordsPerSector do
  62.     begin
  63.      Bios( SelectRecord, CpmRecord ) ;
  64.      Bios( SelectBuffer, Buffer    ) ;
  65.      BiosError:= BiosError or
  66.                  (Bios( ReadRecord )<>0) ;
  67.      CpmRecord:= Succ( CpmRecord ) ;
  68.      Buffer:= Buffer + BytesPerRecord ;
  69.     end ;  { of for }
  70.    Bios( SelectDrive, CpmCurrentDrive ) ;
  71.  
  72.    if BiosError then
  73.      FlagError( 'ReaS: Disk read error' ) ;
  74. end ;  { of ReadSector }
  75.  
  76. procedure WriteSector( Sector, Buffer: Integer ) ;
  77. {*
  78.  * Write one MS-DOS sector from the specified buffer onto disk.
  79.  *}
  80. var
  81.    CpmTrack : Integer ;  { Ordinal of logical track }
  82.    CpmRecord: Integer ;  { Ordinal of record }
  83.    BiosError: Boolean ;  { Completion status of procedure }
  84.    I        : Integer ;  { Loop control variable }
  85. begin
  86.    CpmTrack := (Sector div SectorsPerTrack) ;
  87.    CpmRecord:= (Sector mod SectorsPerTrack) * RecordsPerSector ;
  88.  
  89.    Bios( SelectDrive, MsdosDrive ) ;
  90.    Bios( SelectTrack, CpmTrack   ) ;
  91.    for I:= 1 to RecordsPerSector do
  92.     begin
  93.      Bios( SelectRecord, CpmRecord ) ;
  94.      Bios( SelectBuffer, Buffer    ) ;
  95.      if I=1 then
  96.        BiosError:= (Bios( WriteRecord, 2 )<>0)  { Inhibit pre-read }
  97.      else
  98.        BiosError:= BiosError or
  99.                    (Bios( WriteRecord, 0 )<>0) ;
  100.      CpmRecord:= Succ( CpmRecord ) ;
  101.      Buffer:= Buffer + BytesPerRecord ;
  102.     end ;  { of for }
  103.    Bios( SelectDrive, CpmCurrentDrive ) ;
  104.  
  105.    if BiosError then
  106.      FlagError( 'WriS: Disk write error' ) ;
  107. end ;  { of WriteSector }
  108.  
  109. procedure FlushCache ;
  110. {*
  111.  * The BIOS cache (buffer) is not written until the cache is needed for
  112.  * another sector.  Force the cache to be flushed by reading the first (boot)
  113.  * sector: this sector is never written by this program.
  114.  *
  115.  * BIOS supports a special write type for (CP/M) directory sectors, which
  116.  * causes the cache to be flushed immediatly.  However, this BIOS function
  117.  * also includes a verify read, causing a serious degradation of the transfer
  118.  * speed if used often, for instance in WriteSector.
  119.  *}
  120. var
  121.    Success: Boolean ;  { Read operation completed normally }
  122. begin
  123.    Bios( SelectDrive , MsdosDrive )  ;
  124.    Bios( SelectTrack ,          0 )  ;
  125.    Bios( SelectRecord,          0 )  ;
  126.    Bios( SelectBuffer,  Addr(ClusterBuffer) ) ;
  127.    Success:= Bios( ReadRecord ) = 0     ;
  128.    Bios( SelectDrive, CpmCurrentDrive ) ;
  129.  
  130.    if not Success then
  131.      FlagError( 'FluC: Can''t read the boot sector' ) ;
  132. end ;  { of FlushCache }
  133.  
  134.  
  135.  
  136. procedure ReadFat( FatOrdinal: Integer ) ;
  137. {*
  138.  * Read the MS-DOS File Allocation Table into table FatBuffer.  The
  139.  * supplied FatOrdinal should be in the range 1 through FatsPerDisk.
  140.  *}
  141. var
  142.    Sector: Integer ;  { Ordinal of sector }
  143.    Buffer: Integer ;  { Address of FAT buffer }
  144.    I     : Integer ;  { Loop control variable }
  145. begin
  146.    Sector:= FirstFatSector + FatOrdinal*SectorsPerFat ;
  147.    Buffer:= Addr( FatBuffer ) ;
  148.    for I:= 1 to SectorsPerFat do
  149.     begin
  150.      ReadSector( Sector, Buffer ) ;
  151.      if ErrorDetected then
  152.       begin
  153.        BuildErrorTrace( 'ReaF_' ) ;
  154.        Exit ;
  155.       end ;  { of if }
  156.      Sector:= Succ( Sector ) ;
  157.      Buffer:= Buffer + BytesPerSector ;
  158.     end ;  { of for }
  159. end ;  { of ReadFat }
  160.  
  161. procedure WriteFat( FatOrdinal: Integer ) ;
  162. {*
  163.  * Write the File Allocation Table from table FatBuffer to disk.  The
  164.  * supplied FatOrdinal should be in the range 1 through FatsPerDisk.
  165.  *}
  166. var
  167.    Sector: Integer ;  { Ordinal of sector }
  168.    Buffer: Integer ;  { Address of FAT buffer }
  169.    I     : Integer ;  { Loop control variable }
  170. begin
  171.    Sector:= FirstFatSector + FatOrdinal*SectorsPerFat ;
  172.    Buffer:= Addr( FatBuffer ) ;
  173.    for I:= 1 to SectorsPerFat do
  174.     begin
  175.      WriteSector( Sector, Buffer ) ;
  176.      if ErrorDetected then
  177.       begin
  178.        BuildErrorTrace( 'WriF_' ) ;
  179.        Exit ;
  180.       end ;  { of if }
  181.      Sector:= Succ( Sector ) ;
  182.      Buffer:= Buffer + BytesPerSector ;
  183.     end ;  { of for }
  184. end ;  { of WriteFat }
  185.  
  186. procedure ReadCluster( Cluster: Integer ) ;
  187. {*
  188.  * Read one MS-DOS cluster from disk into the cluster buffer.  The
  189.  * supplied cluster number should be in the range 2 through ClustersPerDisk.
  190.  *}
  191. var
  192.    Sector: Integer ;  { Ordinal of sector }
  193.    Buffer: Integer ;  { Start address of buffer area }
  194.    I     : Integer ;  { Loop control variable }
  195. begin
  196.    Sector:= FirstDataSector + (Cluster-2)*SectorsPerCluster ;
  197.    Buffer:= Addr( ClusterBuffer ) ;
  198.    for I:= 1 to SectorsPerCluster do
  199.     begin
  200.      ReadSector( Sector, Buffer ) ;
  201.      if ErrorDetected then
  202.       begin
  203.        BuildErrorTrace( 'ReaC_' ) ;
  204.        Exit ;
  205.       end ;  { of if }
  206.      Sector:= Succ( Sector ) ;
  207.      Buffer:= Buffer + BytesPerSector ;
  208.     end ;  { of for }
  209. end ;  { of ReadCluster }
  210.  
  211. procedure WriteCluster( Cluster: Integer ) ;
  212. {*
  213.  * Write one MS-DOS cluster from the cluster buffer onto disk.  The
  214.  * supplied cluster number should be in the range 2 through ClustersPerDisk.
  215.  *}
  216. var
  217.    Sector: Integer ;  { Ordinal of sector }
  218.    Buffer: Integer ;  { Start address of buffer area }
  219.    I     : Integer ;  { Loop control variable }
  220. begin
  221.    Sector:= FirstDataSector + (Cluster-2)*SectorsPerCluster ;
  222.    Buffer:= Addr( ClusterBuffer ) ;
  223.    for I:= 1 to SectorsPerCluster do
  224.     begin
  225.      WriteSector( Sector, Buffer ) ;
  226.      if ErrorDetected then
  227.       begin
  228.        BuildErrorTrace( 'WriC_' ) ;
  229.        Exit ;
  230.       end ;  { of if }
  231.      Sector:= Succ( Sector ) ;
  232.      Buffer:= Buffer + BytesPerSector ;
  233.     end ;  { of for }
  234. end ;  { of WriteCluster }
  235.  
  236. function GetFatEntry( Index: Integer ) : Integer ;
  237. {*
  238.  * Return the pointer in the File Allocation Table at a given
  239.  * index (ordinal).  The supplied index should be in the range 0 through
  240.  * ClustersPerDisk.
  241.  *}
  242. var
  243.    Result: Integer ;  { Raw result }
  244.    I     : Integer ;  { Index in FAT array }
  245. begin
  246.      I     := (Index * 3) shr 1 ;
  247.      Result:= FatBuffer[I] + (FatBuffer[I+1] shl 8) ;
  248.      if Odd(Index) then
  249.        Result:= Result shr 4 ;
  250.      GetFatEntry:= Result and $0FFF ;
  251. end ;  { of GetFatEntry }
  252.  
  253. function GetFreeFatEntry( ClOrd: Integer ) : Integer ;
  254. {*
  255.  * Return the ordinal of the next free entry in the FAT.  The search starts
  256.  * at the entry following the specified FAT ordinal.  If there is no free
  257.  * entry in the FAT, an error condition is raised and an out-of-range value
  258.  * is returned.
  259.  *
  260.  * Note: if the disk is full, in the last invokation of GetFatEntry the
  261.  * parameter ClOrd will be out of range.  However, the (rubbish?) value
  262.  * returned by GetFatEntry won't have any effects.
  263.  *}
  264. begin
  265.    repeat
  266.      ClOrd:= Succ( ClOrd ) ;
  267.    until (ClOrd>ClustersPerDisk) or (GetFatEntry(ClOrd)=0) ;
  268.    if ClOrd<=ClustersPerDisk then
  269.      GetFreeFatEntry:= ClOrd
  270.    else
  271.     begin
  272.      FlagError( 'GetFFE: Disk full' ) ;
  273.      GetFreeFatEntry:= $0FFF ;
  274.     end ;  {of if }
  275. end ;  { of GetFreeFatEntry }
  276.  
  277. procedure PutFatEntry( Index, Value: Integer ) ;
  278. {*
  279.  * Put the given value into the FAT entry with ordinal Index.  The supplied
  280.  * index should be in the range 2 through ClustersPerDisk.  The supplied
  281.  * value should be in the same range or it should be $FFF.
  282.  *}
  283. var
  284.    Result: Integer ;  { Intermediate result }
  285.    I     : Integer ;  { Index in FAT array }
  286. begin
  287.      I     := (Index * 3) shr 1 ;
  288.      Result:= FatBuffer[I] + (FatBuffer[I+1] shl 8) ;
  289.      if Odd(Index) then
  290.        Result:= (Result and $000F) + (Value shl     4)
  291.      else
  292.        Result:= (Result and $F000) + (Value and $0FFF) ;
  293.      FatBuffer[I  ]:= Lo( Result ) ;
  294.      FatBuffer[I+1]:= Hi( Result ) ;
  295. end ;  { of PutFatEntry }
  296.  
  297.