💾 Archived View for mirrors.apple2.org.za › archive › apple.cabi.net › FAQs.and.INFO › DiskDrives › … captured on 2023-01-29 at 07:47:25.

View Raw

More Information

-=-=-=-=-=-=-

Path: blue.weeg.uiowa.edu!news.uiowa.edu!uunet!spool.mu.edu!sgiblab!sisters.cs.uoregon.edu!cs.uoregon.edu!news.uoregon.edu!cie-2.uoregon.edu!nparker
From: nparker@cie-2.uoregon.edu (Neil Parker)
Newsgroups: comp.sys.apple2
Subject: Re: apple disk specs, hard and soft
Date: 1 Oct 1994 08:52:37 GMT
Organization: University of Oregon Campus Information Exchange
Lines: 272
Message-ID: <36j80l$1cg@pith.uoregon.edu>
References: <36i1u3$gp8@senator-bedfellow.MIT.EDU>
NNTP-Posting-Host: cie-2.uoregon.edu
Keywords: disk ][, hardware, software

In article <36i1u3$gp8@senator-bedfellow.MIT.EDU> biomorph@athena.mit.edu
(Bayard Wenzel) writes:
>Ok. So i was wondering if someone could tell me about the interface 
>with the drives on the apple2. like, which i/o addresses do what, and
>what exactly they signify. a pointer to some kind of on-line documentation
>would be most ideal, but even the sparcest summary of the card interface
>would be nice.
>
>I could also do with some understanding of the plug to external drives,
>even just a list of what each pin corresponds to (power, gnd, clock, ack,
>req, blah, blah, blah).

The pinouts of the current Apple II disk connectors are listed in Apple
II Miscellaneous Technical Note #6:  IWM Port Description, available on
ftp.apple.com.

I have a file that I wrote up a while ago about the programming interface
to the 5.25-inch disk drive hardware.  I'll attach it below.  If you're
also interested in the 3.5-inch drive on the IIGS, then ftp to
cco.caltech.edu, cd to /pub/apple2/info, and get the file "iwmstuff".

Other things worth reading are _Beneath_Apple_DOS_ and _Beneath_Apple_
_ProDOS_ by Don Worth and Pieter Lechner.

-----(beginning of attached file)-----

The 5.25" drive is controlled by the interface card's I/O locations, found
at memory locations $C0n0 through $C0nF, where "n" is a hexadecimal digit
from 9 to F, depending on what slot the card is in (9 is slot 1, A is slot
2, and so on).  These sixteen I/O locations are paired to form eight
"switches"--referencing location X turns the switch off, and referencing
location X+1 turns it on.

Addr.  Name    Purpose
-----  ----    -------
$C0n0  PHASE0  Stepper motor phase 0
$C0n2  PHASE1  Stepper motor phase 1
$C0n4  PHASE2  Stepper motor phase 2
$C0n6  PHASE3  Stepper motor phase 3
$C0n8  ENABLE  Turn disk drive off or on
$C0nA  SELECT  Select drive 1 or 2
$C0nC  Q6      (see below)
$C0nE  Q7      (see below)

To turn the disk drive on, reference location $C0n9.  To turn it off,
reference location $C0n8.  For example,

DRIVEON   LDA $C089,X
          RTS
DRIVEOFF  LDA $C088,X
          RTS
(In this example and the examples that follow, the X-register is assumed to
contain the desired slot number multiplied by $10--e.g. for slot 6, store
a $60 in the X-register.)

After turning the drive on, your program should delay for a while before
doing any reading or writing, in order to give the disk drive motor time to
come up to full speed.  A delay of about one second is sufficient (DOS 3.3
is able to reduce the delay by watching the read data until it starts to
change).

To select drive one, reference $C0nA.  To select drive two, reference
$C0nB.  For example,

DRIVE1    LDA $C08A,X
          RTS
DRIVE2    LDA $C08B,X
          RTS

The Q6 and Q7 switches are used together to control several operations:
reading, writing, and testing the write-protect notch.

To read data from the disk drive, first reference location $C0nE--this
activates "read" mode.  Then wait until the high bit at $C0nC turns on, and
read the data byte from $C0nC.

          LDA $C08E,X
          ...
READLP    LDA $C08C,X
          BPL READLP
          STA DATA

To sense the write-protect switch, reference location $C0nD, and read the
high bit of $C0nE.  If the high bit is set, then the disk is
write-protected.

          LDA $C08D,X
          LDA $C08E,X
          BMI WRPROT

Of all the operations the disk drive can perform, writing is probably the
most difficult.  The hardware writes one bit every four cycles, which means
your program has to feed bytes to the controller at precise 32-cycle
intervals.  The controller will not tell you when it's time to write the
next byte--your code has to figure this out all by itself, by carefully
counting out the execution times of the instructions in the write loop.

To prepare the controller for writing, first test the write-protect switch.
Then turn on "write" mode by referencing $C0nF.  The byte written to $C0nF
or $C0nD will be stored within the controller, and your program should then
immediately reference $C0nC, which causes the controller to start
transmitting the bits to the disk.  When your program is finished writing,
it should immediately reference $C0nE to turn off "write" mode.

          LDA $C08D,X
          LDA $C08E,X
          BMI ERROR
          LDA DATA1     (absolute load = 4 cycles)
          STA $C08F,X   (5 cycles)
          ORA $C08C,X   (4)
          JSR PAUSE     (6)
          LDA DATA2     (4)
          STA $C08D,X   (5)
          ORA $C08C,X   (4)
          JSR PAUSE     (6)
          ...
          LDA DATALAST  (4)
          STA $C08D,X   (5)
          ORA $C08C,X   (4)
          JSR PAUSE     (6)
          NOP           (2)
          NOP           (2)
          ORA $C08E,X   (4)
          RTS

PAUSE     PHA           (3)
          PLA           (4)
          RTS           (6)

Important things to notice in the above code:

     * The first byte is written by storing at $C0nF, and subsequent bytes
       are written by storing at $C0nD.
     * There are exactly 32 cycles between references to $C0nD, and exactly
       32 cycles between references to $C0nC.
     * After writing the final byte, there is a delay before turning off
       write mode, to give the bits time to get written.
     * Interrupts must be disabled when writing.  If an interrupt were to
       occur, the timing would become hopelessly lost.  (Interrupts should
       also be disabled when reading, to avoid missing data.)

In practice, the above routine is horribly impractical for writing actual
data--more likely you would use a loop to write a sector of data at a time.
When writing the loop, be sure to remember the timing nuances of branches
taken or not taken, as well as indexing or branching across a page
boundary.  (If you're on a IIGS, you don't need to worry about system
speed--the system automatically switches to "slow" speed when the disk
drive is turned on.)

If writing is the hardest action to perform, then moving the arm from one
track to another must be the hardest to explain.

The arm is attached to a stepper motor with four positions.  This motor may
be though of like the hand of a clock, which can point to 12 o'clock
("phase 0"), 3 o'clock ("phase 1"), 6 o'clock ("phase 2") or 9 o'clock
("phase 3").  When the "hand" moves clockwise, the read/write head moves
inward, toward higher-numbered tracks, and when the hand moves
counter-clockwise, the head moves outward toward lower-numbered tracks.  A
complete revolution of the "hand" causes the head to pass over four tracks.

At each of the four "clock positions," or "phases," there is an
electromagnet, and the "hand" may be attracted toward a position by turning
on the corresponding magnet and waiting.  The "hand" may be made to revolve
around the "clock" by doing this several times in succession--for example
to move clockwise from 12 o'clock back to 12 o'clock,

     Turn on the 3 o'clock magnet ("phase 1")
     Wait
     Turn off the 3 o'clock magnet
     Turn on the 6 o'clock magnet ("phase 2")
     Wait
     Turn off the 6 o'clock magnet
     Turn on the 9 o'clock magnet ("phase 3")
     Wait
     Turn off the 9 o'clock magnet
     Turn on the 12 o'clock magnet ("phase 0")
     Wait
     Turn off the 12 o'clock magnet

After this is done, the head will be positioned four tracks farther inward
than it was previously.

Each position of the "clock hand" corresponds to a track on the disk.
Track 0 is "underneath" the 12 o'clock position.  One would probably expect,
then, to find track 1 under the 3 o'clock position, track 2 under 6 o'clock
and so forth.

Unfortunately, this isn't quite the case.  The read/write head on an Apple
drive is wider than the tracks, so if data were recorded on track 1, some
of it would "slop over" and interfere with the data on track 0 and track
2.  Therefore, only the even-numbered tracks are actually used on a normal
disk.  The operating system multiplies all track numbers by two before
moving the head--the operating system's track 1 is on physical track 2
(under the 6 o'clock position), the operating system's track 2 is on
physical track 4 (under the 12 o'clock position), etc.  The 3 o'clock and 9
o'clock positions are unused on normal disks (but they are often used on
copy-protected disks, and are usually called "half tracks").

The disk hardware provides no means for determining what track the head is
currently positioned over, or what clock position the stepper motor is
pointing to.  Therefore, the disk I/O routines must keep their own records
of the current head position.  If the I/O routines don't know what the
current track is, the usual method of coping with the situation is to
assume that we're currently on some high-numbered track beyond the
innermost position, and move the head from there to track 0.  This is what
causes the horrible grinding sound when a 5.25" disk boots.

Here are a couple of routines to move the head to any desired track:

; TRKMOVE -- move the head to any track on a 5.25" disk.
; Inputs: A-reg = desired track
;         X-reg = slot * 16
; Assumes the disk drive has already been turned on
;
PHASE0   EQU $C080           ;Stepper motor phase 0
;
WAIT     EQU $FCA8           ;Monitor routine to waste time
;
TRKMOVE  ASL                 ;(Some assemblers require ASL A here)
TRKMOVE1 STX SLOT            ;Save slot number
         SEC
         SBC CURPH           ;Compare with current position
         BEQ DONE            ;Quit if already there
         BCS IN1             ;Moving inward?
         EOR #$FF            ;No--take 2's-complement of track difference...
         TAY                 ;...and save in Y reg
         INY
         BCC OUT1            ;(branch always taken)
IN1      TAY                 ;Save track diff in Y reg
IN2      INC CURPH           ;Move one track inward
         BCS STEP            ;(branch always taken)
OUT1     DEC CURPH           ;Move one track outward
STEP     PHP                 ;Save step direction (in C flag)
         LDA CURPH
         AND #3              ;Convert track to phase number
         ASL                 ;(Some assemblers require ASL A here)
         ORA SLOT
         TAX
         LDA PHASE0+1,X      ;Turn on motor phase
         LDA #$56
         JSR WAIT            ;Waste some time
         LDA PHASE0,X        ;Turn off motor phase
         PLP
         DEY                 ;More steps left?
         BEQ DONE            ;If not, quit
         BCS IN2             ;If going inward, do it again
         BCC OUT1            ;If going outward, do it again
DONE     RTS
CURPH    DS  1               ;Space to save current track number
SLOT     DS  1               ;Space to save slot number
;
; RECAL -- routine to recalibrate head to track 0
; Call this if you don't know what track you're on
; Inputs:  X-reg = slot number * 16
; Assumes disk drive is already turned on
; (Warning:  This routine is noisy!)
;
RECAL    LDA #$50            ;Pretend we're on phase 80 (track 40)
         STA CURPH
         LDA #0              ;Go to track 0
         JMP TRKMOVE1        ;Do it

If you want to position the head over one of the unused tracks (the 3
o'clock and 9 o'clock tracks), enter the subroutine at TRKMOVE1 instead of
TRKMOVE.  This skips the conversion of the operating system's track number
into the physical track number.

           - Neil Parker
--
Neil Parker                 No cute ASCII art...no cute quote...no cute
nparker@cie-2.uoregon.edu   disclaimer...no deposit, no return...
nparker@cie.uoregon.edu     (This space intentionally left blank:           )