(c)  Copyright 1989 Commodore-Amiga, Inc.   All rights reserved.
The information contained herein is subject to change without notice, and 
is provided "as is" without warranty of any kind, either expressed or implied.  
The entire risk as to the use of this information is assumed by the user.




                   Amiga Low-Level Disk Access

                        by Bryce Nesbitt



Some high-performance games for the Amiga have been released recently which
ignore the operating system and take over the machine.  While this practice 
is discouraged, it is allowable.  However, some of these games make direct
use of the floppy disk hardware in an incorrect manner.  Such misuse is NOT 
acceptable.

Similarly, certain books by major publishers have described direct access
techniques for the Amiga's disk hardware which will NOT work with all
Amigas.  Commodore uses floppy disk drives manufactured by several different 
vendors.  These vendors often upgrade or modernize their disk drive lines, 
usually making the older drive models unavailable.  For this reason, it is 
impossible for a developer to test with all possible drive types.  In order 
to work across this broad spectrum of drives, certain rules must be 
followed.

The routines presented here will allow you to get low-level access to the
Amiga's floppy disk hardware without sacrificing compatability.  Three 
functions are provided to correctly implement the three most critical drive 
operations, namely, motor on, motor off and step.  Also included is a simple
test module which shows how to use the routines in your application.




       Disk Routine      Purpose
       ------------      -------------   

       MOTORON           Turn the motor on, and properly wait for the
                         drive to reach full speed.

       MOTOROFF          Turn off and deselect all drives

       STEPHEAD          Step the head, and properly wait for the 3.0
                         millisecond step delay on any speed CPU.

       TEST              Test program showing use of above functions.



By using these routines you can avoid the hardware dependencies that make
your software unloadable on some Amigas and the customer support headaches
that go along with it.





*  opt l+,c+,w-
;
; Low-level "take over the machine" disk drive functions.
;
; *** FOR USE ONLY WHEN YOU HAVE TAKEN OVER THE MACHINE ***
;
; Written by Bryce Nesbitt, Commodore-Amiga, Inc.
;
;****** Externally visible functions

        XDEF    MOTORON     ;Turn drive 0 motor ON & wait for READY.
        XDEF    MOTOROFF    ;Turn off all drive motors.
        XDEF    STEPHEADS   ;Step the drive head & wait properly.


;****** Hard-coded I/O register locations
;
CIAA_PRA        EQU $BFE001 ;Port "A" on CIA "A".
CIAB_PRB        EQU $BFD100 ;Port "B" on CIA "B".
CIAA_TALO       EQU $BFE401 ;Timer A low
CIAA_TAHI       EQU $BFE501 ;Timer A high
CIAA_ICR        EQU $BFED01 ;Interrupt control register
CIAA_CRA        EQU $BFEE01 ;Timer A control


;;;;;;; MOTORON ;;;;;;;
;
; Turn off the motors of drives 1-3, then turn on drive 0.
; This function returns when drive 0 is ON and spinning at full speed.
; If drive 0 is already spinning, this function returns very quickly.
;
; The direction and side lines are untouched.
;
MOTORON:
                or.b    #$F9,CIAB_PRB   ;Set motor line to off, deselect
                                         ;all drives, and unset STEP line.
                and.b   #$8F,CIAB_PRB   ;Select drives 1-3 so they see the
                                         ;motor off setting
                or.b    #$70,CIAB_PRB   ;Deselect drives 1-3

                and.b   #$7F,CIAB_PRB   ;Set motor ON.  This must be done
                                         ;*BEFORE* selecting drives!
                and.b   #$F7,CIAB_PRB   ;Select drive zero.  The drive will
                                         ;"remember" the motor setting
                                         ;if the motor was already on,
                                         ;nothing happens

motor_wait      btst.b  #5,CIAA_PRA     ;Check READY line
                bne.s   motor_wait      ;Busy-wait until drive is ready
                rts






;;;;;;; MOTOROFF ;;;;;;;
;
; Turn OFF all drive motors.
;
MOTOROFF:
                or.b    #$F8,CIAB_PRB   ;Deselect all drives and set motor
                                         ;line to OFF
                and.b   #$87,CIAB_PRB   ;Select all drives so they see the
                                         ;new motor setting.
                or.b    #$F8,CIAB_PRB   ;Deselect all drives
                rts


;;;;;;; STEPHEADS ;;;;;;;
;
; D0 must contain zero to step the heads inward, and -1 to step the
; heads toward the outside of the disk.
;
; The heads will step in the direction indicated.  After stepping this
; function will do a processor-independant wait for the required
; 3.0 millisecond step delay.  Note that some disk drives do not
; require a full 3.0 milliseconds, but others do.  It is not safe
; to release a commercial product with a shorter step delay.
;
; Note that the STEP line must always start out high, be pulsed
; low, then return high.
;
; Using this timer chip method and interrupts, it is easy to create
; a loader that keeps on loading while your title music plays.
;
STEPHEADS:
                and.b   #2,d0           ;Remove garbage bits
                or.b    d0,CIAB_PRB     ;Set direction register FIRST

                ;(Try to be a little bit slow about pulsing the step line)
                bclr.b  #0,CIAB_PRB     ;Pulse STEP line low
                bset.b  #0,CIAB_PRB     ;Return STEP high
;
; Use the timer chip to waste 3.0 milliseconds
;
; The base Amiga crytal frequecies are:
;           NTSC    28.63636 Mhz
;           PAL     28.37516  Mhz
; The two 16 bit timers on the 8520 chips each count down at 1/10
; the CPU clock, or .715909 Mhz.  That works out to 1.3968255
; microseconds per count.  Under PAL the countdown is a hair
; slower, .709379 Mhz.
;
; To wait 1/100 second would require waiting 10,000 microseconds.
; The timer register would be set to (10,000 / 1.3968255 = 7159).
;
; To wait 3 milliseconds would require waiting 3000 microsecsonds.
; The register would be set to (3000 / 1.3968255 = 2148).
;
; See the hardware manual for more information on the 8520 chips.
;

;----Setup (really only needs to be done once)
                move.w  #$7fff,$dff09a      ;Kill all custom chip interrupts
;----This sets timer A to one-shot mode.
                move.b  CIAA_CRA,d0         ;Set control register A
                and.b   #%11000000,d0       ;Don't trash the 60/50Hz flag
                or.b    #%00001000,d0       ;or serial direction bits
                move.b  d0,CIAA_CRA
                move.b  #%01111111,CIAA_ICR ;Clear all 8520 interrupts
;----end setup

;----Set time (low byte THEN high byte)
                move.b  #(2148&255),CIAA_TALO  ;Mask off low part
                move.b  #(2148>>8),CIAA_TAHI  ;Shift high part 8 bits

;----Wait for the timer to count down
busy_wait:      btst.b  #0,CIAA_ICR         ;Wait for timer expired flag
                beq.s   busy_wait
                rts


;;;;;;; TEST ;;;;;;;
;
; Quick, nasty test program
;
*               INCDIR  "inc:"
                INCLUDE "exec/types.i"
                INCLUDE "exec/ables.i"

                XREF    _LVODisable


TEST:           move.l  4,a6
                jsr     _LVODisable(a6)
                bsr     MOTORON

                moveq   #10,d3          ;Ten full seeks before end
fullseek:
                bset.b  #1,CIAB_PRB     ;Set direction to OUTWARD
                moveq   #80-1,d2        ;80 tracks
test4           bsr     STEPHEADS
                btst.b  #4,CIAA_PRA     ;Check track 00 sensor
                dbeq    d2,test4        ;Decrement and branch until
                                        ;EQual or count exceeded
                moveq   #80-1,d2
                bclr.b  #1,CIAB_PRB     ;Set direction to INWARD
test3           bsr     STEPHEADS
                dbra    d2,test3

                dbra    d3,fullseek

                bsr     MOTOROFF
fish            bra.s   fish
;
; We have killed the operating system, so this tester never exits
;
