Classic Computer Magazine Archive COMPUTE! ISSUE 21 / FEBRUARY 1982 / PAGE 118

THE OSI® GAZETTE

Part II:
A Small Operating System: OS65D, The Disk Routines

T. R. Berger
Coon Rapids, MN

Editor's Note: Part I appeared last month. Here, the author presents a map of the disk routines.—RTM

Let's turn to track zero. Exactly one ms. after the index hole a two byte address is recorded on the disk in high byte-low order. This address is read by the ROM on boot. It is the start address for loading track zero into memory. Next comes the number of pages in track zero. Finally, that many pages of data are written on the track. There are no track start or stop markings. After track zero is loaded, the computer always jumps to $2200. Hopefully, track zero has been loaded in that vicinity. It would appear that OSI did not think the track zero format over very carefully.

Subroutine Descriptions

Most of the disk routines are self-explanatory. Because these routines are far more involved than those in the kernel, many more flow charts are needed. Let's run through the memory map in order, commenting on special properties of certain subroutines.

The timing routines at $2678, $267A, and $26A2 are independent of the system clock. The wait time in the routines at $2700, $289F, and $28A4 should be divided by T if the system clock is T MHZ.

OS65D does not use binary track numbers, but BASIC does. Thus BASIC uses $26A6, but OS65D enters this routine at $26BC with the BCD track number in the accumulator. With a binary track number in the accumulator, this routine may be entered at $26A9. It will move the disk head over the correct track after some error checking.

The sequence beginning at $2728 may be viewed as the standard startup to read or write a track or sector. It puts the head on the disk, finds the index hole, then initializes the disk data ACIA.

The EXAMINE command uses $2739 to load the entire contents of a track into memory without regard to error checking, track formatting, or sectoring. This type of command is only possible with the asynchronous data format used by OSI. If you crash a track, this command can prove invaluable in retrieving what may remain. I view this routine as a utility. It should reside on the disk and not in memory, unless needed. The initialize routine at $2768 used on a full disk falls in the same category. Such programs as these should be transient, i.e. only called when needed.

The major "Save a Sector" routine begins at $27D7. It uses the data in $265E-$2661. Most of OS65D's disk data is stored in page zero. Because Zpage is swapped out when BASIC comes in, the most important data is repeated in $265C-$2662. BASIC passes its values to these latter locations. LOAD and SAVE routines must then move this data to Zpage. Since OS65D can put information directly into Zpage, it puts the save vector into $FE, $FF directly, entering the Save routine at $27E1. Except when SAVE or CALL are used, all saving is done in Sector one for 12 ($OC) pages on 8" floppies and for eight pages on minifloppies. After a write, the sector is reread and compared with memory. If the comparison fails, the sector is reread again. This may occur up to four times. If comparison still fails, another attempt is made to write the sector. If comparison fails after four rereads again, the operation is aborted with Error #2. To my recollection, I've never seen Error #2 occur. It might happen on an old worn disk, on a midnight special, or with a very dirty head.

The major "Read a Sector" routine is $295D. It uses data in $265-E-$2662. Again OS65D may enter this routine at $2967 if the load vector at $FE, $FF has been set. This program tries to read a sector seven times. The only error check (other than sector seek errors which abort immediately) is a parity check for each byte. If, after seven tries, a read still fails, then the head is moved down then up one track. This whole process may be repeated up to four times before Error #1 is reported. This error also seems to be very rare.

Both read and save routines use the sector seeking routine at $28C4 which, in turn, calls $2998. Further, they both use a dual purpose routine at $2905. If the accumulator is zero on entry, this routine reads to memory. If it is nonzero, then the routine compares with memory. The actual read and compare loops within this routine are separate. With 8&inch; floppies and a 1 MHZ clock, the 6502 is not fast enough to get from one disk byte to the next if the read and compare loops are combined into one. As it stands, the compare loop just barely returns in time for the next comparison. With a 2 MHZ clock there is plenty of time.

I view the sector directory routines at $29F3 and $2A41 as utilities. They do not need to be resident in memory.

Machine language routines may access the disk directly. For example, to write a sector, locations $265E-$2662 should be assigned correct values. The following segment of code will write a sector to the disk.

10 JSR $26A6 ;Move head to track
20 JSR $2754 ;Engage head, find start of track
30 JSR $27D7 ;Write sector
40 JSR $2761 ;Disengage head
50 RTS

If the write address is already in $FE, $FF then $27D7 may be entered at $27E1. In this case, lines 20-40 may be replaced by JSR $2CA7, a kernel routine.

To read a sector, again assign correct values to $265E-$2662 then perform the following.

10 JSR $26A6 ;Move head to track
20 JSR $2754 ;Engage head, find start of track
30 JSR $295D ;Read sector
40 JSR $2761 ;Disengage head
50 RTS

If the read address is already in $FE, $FF then $295D may be entered at $2967. In this case, lines 20-40 may be replaced by the kernel routine:

JSR $2B1A

When we discuss the I/O section of OS65D we will see additional ways to read from and write to the disk.

References:

1. Jefferson Harman, "IBM Compatible Disk Drives", Byte October 1979, p. 100

2. Ira Rampil, "A Floppy Disk Tutorial", Byte December 1977, p. 24

3. Les Solomon, "BASICS of Computer Disk Systems", Popular Electronics November 1980, p. 53

MAP – OS65D DISK HANDLER

DISK-MEMORY DATA

265C DRIVE NUMBER
265D CURRENT BCD TRACK NUMBER
265E SECTOR NUMBER
265F PAGE LENGTH OF SECTOR
2660 LOW BYTE LOAD/SAVE VECTOR
2661 HIGH BYTE LOAD/SAVE VECTOR
2662 BINARY TRACK NUMBER

DISK-Z PAGE

E5 LAST TRACK OF FILE BEING HANDLED
F6 NUMBER OF RETRIES ON WRITE
F7 NUMBER OF HEAD MOVE RETRIES ON READ
F8 NUMBER OR READ RETRIES BEFORE HEAD MOVE
F9 SECTOR COUNT
FA TARGET TRACK NUMBER ON SEEK
FB SECTOR NUMBER READ ON DISK
FC STACK POINTER (IN $29F3)
FD SECTOR PAGE COUNT (IN $27D7)
FE SYSTEM POINTER. USED AS
FF LOAD AND SAVE VECTOR BY DISK

Subroutines–OS65D Disk Handler

2663 Home the Disk. Move the disk head to track 0.
2678 Wait 12 ms.
267A Wait X ms.
2683 Step up one track toward track 76.
268A Step down one track toward track 0.
26A2 Wait 8 ms.
26A6 Fetch binary track number from 2662 then:
26A9 Convert track number to BCD then:
26BC Check for track 0-76 BCD, check for drive ready, move disk head to track, adjust head current, and if an error occurs, abort and send an error message via 2A4B.
2700 Wait 20 Y + 7 microseconds (1 MHZ clock).
2708 Adjust head current.
271D Find trailing edge of index hole.
2728 Engage head then:
272B Find index hole then:
272E Initialize disk ACIA.
2739 Engage head, read from index hole full around to index hole, then quit.
2754 Head down.
2761 Head up.
2768 Initialize full disk.
277D Initialize one track.
27C2 Send a byte to the disk.
27CD Fetch a byte from the disk.
27D7 Fetch sector save vectors then:
27E1 Save a sector.
289F Wait 800($FA) microseconds.
28A4 Wait 100Y microseconds.
28B0 Fetch a byte from the disk. Abort with an error message if over the index hole.
28C4 Find the end of the sector preceding the one in 265E.
2905 Read a sector to or compare a sector with memory.
295D Fetch disk read vector then:
2967 Read and reread a sector to memory, quit if successful or the full number of retries are exhausted.
2998 Find the end of the present sector.
29C6 Select the drive in 265C then:
29DA Check if the drive is ready.
29EB 8 drive select data bytes.
29F3 Output a sector directory.
2A41 Output subroutine for 29F3.