/*
 *        Megamax C inline ASM version of Twister.
 *        Converted from AS68 format  dlm  12/14/86.
 *        AS68 version by David Small before that date.
 *        Used for the MegAMin HD backup program.
 */

/* routine that are callable from C are: */
extern twister();

/* global variables */
int thedisk, dblsided, sectoroffset;   /* input parameters */
long buffer;

int badflag;                           /* bad sector error flag */

/* local variables */
static int theside, thetrack, twistsectorno, sectorno, retrycnt,
           cdev, ctrack, csect, cside, ccount, A7t, interlv,
           virgin, def_error, curr_err;
static long cdma, edma, tmpdma, saveA2;

/* now the defines (AS68 equ's) */

/*   tunable values */
#define retries   2           /* default # of retries -1 */
#define midretry  1           /* "middle" retry, when to reseek  */
#define timeout   0x40000     /* short timeout, motor already on */
#define ltimeout  0x60000     /* long timeout, to startup motor  */

/*   Floppy state variables in DSB: RAM usage */
#define recal     0xff00      /* recalibrate flag                */
#define dcurtrack 0           /* current track number            */
#define dseekrt   dcurtrack+2 /* seek rate                       */
#define dsbsiz    dseekrt+2   /* size of a DSB                   */

/* hardware equates */
/* DMA chip         */
#define diskctl     0xffff8604     /* disk controller data access */
#define fifo        0xffff8606     /* DMA mode control / status   */
#define dmahigh     0xffff8609     /* DMA base high               */
#define dmamid      0xffff860b     /* DMA base mid                */
#define dmalow      0xffff860d     /* DMA base low                */

/* 1170 select values    */
#define cmdreg      0x80           /* select command register    */
#define trkreg      0x82           /* select track register      */
#define secreg      0x84           /* select sector register     */
#define datareg     0x86           /* select data register       */

/* GI sound chip (drive a/b select lines and side select) */
#define giselect    0xffff8800     /* (W) sound chip register select */
#define giread      0xffff8800     /* (R) sound chip read data   */
#define giwrite     0xffff8802     /* (W) sound chip write data  */
#define giporta     0x0e           /* GI register # for i/o port A */

/* 68901 mfp chip */
#define mfp         0xfffffa00     /* mfp base                   */
#define gpip        mfp+1          /* general purpose i/o        */

/* ROM burn dates */
#define old_rom  0x11201985L
#define new_rom  0x04221987L

#define rom_date 0x00fc0018L		/* rom burn date address */

/* misc defines */
#define seekrate 3
#define dsb0old  0xa06
#define dsb0new  0xa4c		/* for the Mega ROMs */
#define dsb1old  0xa0a
#define dsb1new  0xa50
#define flock    0x43e

asm {          /* start of inline ASM */

/*
 *   All the following is munged code from AS68 (that's why the
 *   weird format).  The AS68 code was munged from the BIOS
 *   source.  And most of this is from the FDC article in Start
 *   issue number 3.
 *
 *   Anyway, we apologize for the mess, but heh it works.
 *
 *   Oh yes.  The labels are usually on nops, not empty lines.  Thats
 *   because AS68 occasionally pukes on labels on empty lines.  And
 *   I didn't take the time to remove them.  (Megamax doesn't care.)
 *
 */

;****************************************************************
; Twister: Faster formatter (zipformat) hack.  MM version       *
; Copyright (c) 1986, 1987 START Magazine (as usual)            *
; Written by David Y. Small & Dan Moore                         *
;****************************************************************
;                                                               *
;               Dedication:                                     *
;                                                               *
;     For Bill The Cat: because he's twisted, too.              *
;                                                               *
;****************************************************************
;
; code begins.
;
;  PASS ME THIS STUFF DAN! Then SHAVE! For God's sakes! What
; are you trying to do, look like Fidel Castro?
;
; And get SOME BEER in here okay? Sheesh!
;
; input integers (if coming from C):
;
; dblsided: 0000 or ffff
; thedisk: 0 = a, 1 = b
;*************************************************************


;********************************************************
; Frammatter                                            *
;********************************************************
twister:  move.l    A2, saveA2(A4)      ; everything else saved by the Supexec

        clr.w       badflag(A4)         ; assume no errors
;
;*** Init vars for formatting loop
;
        move.w  #0,thetrack(A4)     ; start at track 0

        move.w  #1,twistsectorno(A4) ; twister value
                               
trackloop: nop                  ; comes here for subseq tracks


;***** FRONT SIDE ***********
;**** Setup stack: .. based on read sec command, tweaked for frammat

        move.w  #0xe5e5,-(A7)    ; virgin data -- e5's work okay
        move.l  #0x87654321,-(A7) ; magic # to make format work / fmt only
        move.w  #1,-(A7)        ; sector interleave factor / fmt only
        move.w  #0,-(A7)        ; ** side.w (relevant) / side: FRONT
        move.w  thetrack(A4),-(A7)  ; ** track.w (relevant) / same
        move.w  #10,-(A7)       ; sector.w (irrelevant) / sectors per track
        move.w  thedisk(A4),-(A7)   ; ** device.w  (relevant) / same
        move.l  #0,-(A7)        ; dummy.l (irreleveant) / same
        move.l  buffer(A4),-(A7)   ; ** buffer address.l (relevant) / same
        jsr     _flopfmt
        adda.l  #24,A7          ; Fix stack.
;****
; Jazz twistsectorno(A4). Look at what it ended up as; set it to
; the next track twist depending on that.
;
; It will end up as "+1" from the last sector formatted, because
; the formatter bumps it up.
;
        cmpi.w  #1,twistsectorno(A4)        ; 0-1 transition
        beq     fgoto1
        cmpi.w  #9,twistsectorno(A4)        ; 1-2 transition
        beq     fgoto2
        cmpi.w  #7,twistsectorno(A4)        ; 2-3 transition
        beq     fgoto3
        cmpi.w  #5,twistsectorno(A4)        ; 3-4 transition
        beq     fgoto4
        cmpi.w  #3,twistsectorno(A4)        ; 4-0 transition
        beq     fgoto0
        
        dc.b   0x4a
        dc.b   0xfc                 ; oops, die (illegal instruction)
;*****
; Really class coding, eh? Oh,well, it's easy and it works, which
; twelve other fancy ways of doing this *don't*.
;
fgoto1: move.w  #0x9,twistsectorno(A4)       ; 9,a,1,2,3,4,5,6,7,8
        bra     fkeepformatting
fgoto2: move.w  #0x7,twistsectorno(A4)       ; 7,8,9,a,1,2,3,4,5,6
        bra     fkeepformatting
fgoto3: move.w  #0x5,twistsectorno(A4)       ; 5,6,7,8,9,a,1,2,3,4
        bra     fkeepformatting
fgoto4: move.w  #0x3,twistsectorno(A4)       ; 3,4,5,6,7,8,9,a,1,2
        bra     fkeepformatting
fgoto0: move.w  #0x1,twistsectorno(A4)       ; 1,2,3,4,5,6,7,8,9,a
        bra     fkeepformatting
        nop
;*****
fkeepformatting: nop
;*****
; now, do a verify on those sectors.
;**** Setup stack: .. based on read sec command, tweaked for frammat

        tst.w   sectoroffset(A4)   ; no verify if 11 to 20 sector numbering
        bne     nover1

        move.w  #0xa,-(A7)       ; count.w 2
        move.w  #0,-(A7)        ; ** side.w (relevant) / side: FRONT 4
        move.w  thetrack(A4),-(A7)  ; ** track.w (relevant) / same 6
        move.w  #0x1,-(A7)       ; sector.w (relevant) / starting sector 8
        move.w  thedisk(A4),-(A7)   ; ** device.w  (relevant) / same 0xa
        move.l  #0,-(A7)        ; dummy.l (irreleveant) / same 0xe
        move.l  buffer(A4),-(A7)   ; ** buffer address.l (relevant) / same 0x12

        move.w  #19,-(A7)       ; do BIOS _flopver 0x14
        trap    #14
        adda.l  #20, A7        ; fix stack.

        tst.l   D0
        bne     badsecs

;****

;***** BACK SIDE ******       (How kinky Dave.  What _are_ you talking about?)

nover1:   tst.w   dblsided(A4)
          beq     nobackside

;**** Setup stack: .. based on read sec command, tweaked for frammat

        move.w  #0xe5e5,-(A7)    ; virgin data -- e5's work okay
; and with a virgin.  My, you really are weird Dave.
        move.l  #0x87654321,-(A7) ; magic # to make format work / fmt only
        move.w  #1,-(A7)        ; sector interleave factor / fmt only
        move.w  #1,-(A7)        ; ** side.w (relevant) / side: BACK
        move.w  thetrack(A4),-(A7)  ; ** track.w (relevant) / same
        move.w  #10,-(A7)       ; sector.w (irrelevant) / sectors per track
        move.w  thedisk(A4),-(A7)   ; ** device.w  (relevant) / same
        move.l  #0,-(A7)        ; dummy.l (irreleveant) / same
        move.l  buffer(A4),-(A7)   ; ** buffer address.l (relevant) / same
        jsr     _flopfmt
        adda.l  #24,A7          ; Fix stack.
;*****
;
; Jazz twistsectorno(A4). Look at what it ended up as; set it to
; the next track twist depending on that.
;
; It will end up as "+1" from the last sector formatted, because
; the formatter bumps it up.
;
        cmpi.w  #1,twistsectorno(A4)        ; 0-1 transition
        beq     goto1
        cmpi.w  #9,twistsectorno(A4)        ; 1-2 transition
        beq     goto2
        cmpi.w  #7,twistsectorno(A4)        ; 2-3 transition
        beq     goto3
        cmpi.w  #5,twistsectorno(A4)        ; 3-4 transition
        beq     goto4
        cmpi.w  #3,twistsectorno(A4)        ; 4-0 transition
        beq     goto0

        dc.b    0x4a
        dc.b    0xfc                 ; oops, die

;
goto1:  move.w  #0x9,twistsectorno(A4)       ; 9,a,1,2,3,4,5,6,7,8
        bra     keepformatting
goto2:  move.w  #0x7,twistsectorno(A4)       ; 7,8,9,a,1,2,3,4,5,6
        bra     keepformatting
goto3:  move.w  #0x5,twistsectorno(A4)       ; 5,6,7,8,9,a,1,2,3,4
        bra     keepformatting
goto4:  move.w  #0x3,twistsectorno(A4)       ; 3,4,5,6,7,8,9,a,1,2
        bra     keepformatting
goto0:  move.w  #0x1,twistsectorno(A4)       ; 1,2,3,4,5,6,7,8,9,a
        bra     keepformatting
        nop
;
keepformatting: nop             ; entry after twisting.
;

;**** Setup stack: .. based on read sec command, tweaked for frammat
        
        tst.w   sectoroffset(A4)   ; no verify for strange sector numbers
        bne     nobackside

        move.w  #0xa,-(A7)       ; count.w 2
        move.w  #1,-(A7)        ; ** side.w (relevant) / side: BACK 4
        move.w  thetrack(A4),-(A7)  ; ** track.w (relevant) / same 6
        move.w  #0x1,-(A7)       ; sector.w (relevant) / starting sector # 8
        move.w  thedisk(A4),-(A7)   ; ** device.w  (relevant) / same 0xa
        move.l  #0,-(A7)        ; dummy.l (irreleveant) / same 0xe
        move.l  buffer(A4),-(A7)   ; ** buffer address.l (relevant) / same 0x12

        move.w  #19,-(A7)       ; do BIOS _flopver 0x14 (why not)
        trap    #14
        adda.l  #20, A7         ; fix stack

        tst.l   D0
        bne     badsecs         ; wham

;****
nobackside: nop                 ; entry if not DS  (well at least this isn't kinky Dave)

; add 1 to thetrack. If 80, quit.
        addi.w   #1, thetrack(A4)
        cmpi.w  #80, thetrack(A4)
        bne     trackloop       ; "do another"

        bra     gemexit         ; Continue, etc, and so forth

;*********
badsecs:  move.w #0xffff, badflag(A4)  ; bad sectors found

;**************
;
; End. Exit to calling routine.
;
gemexit:  movea.l saveA2(A4), A2  ; only reg not saved by Supexec
          rts

;******************************************************
;
;------------------------------------------------------------------------
;       130-ST / 520-ST                                                 :
;       Floppy Disk Driver                                              :
;       (C)1985 Atari Corp.                                             :
;       From the FDC article (Start issue 3); shortened to just         :
;       the formatter routine and the low level I/O.                    :
;                                                                       :
;------------------------------------------------------------------------
;
;************************************************************
;
; _flopfmt - format a track
; Passed (on the stack):
;       0x1a(A7) initial sector data
;       0x16(A7) magic number
;       0x14(A7) interleave
;       0x12(A7) side
;       0x10(A7) track
;        0xe(A7) A7t(A4)
;        0xc(A7) drive
;        0x8(A7) pointer to state block
;        0x4(A7) dma address
;        0x0(A7) [return]
;
; Returns:      EQ: track successfully written.  Zero.W-terminated list of
;               bad sectors left in buffer (they might /all/ be bad.)
;
;               NE: could not write track (write-protected, drive failure,
;               or something catastrophic happened).
;-
_flopfmt:
        cmpi.l   #0x87654321, 0x16(A7)      ; check for magic# on stack
        bne     flopfail                ; no magic, so we just saved the world
;       bsr     change                  ; check for disk flip
;       moveq   #e_error,D0             ; set default error number
        bsr     floplock                ; lock floppies, setup parms
        bsr     select                  ; select drive and side
        move.w  0xe(A7),A7t(A4)              ; save sectors-per-track
        move.w  0x14(A7),interlv(A4)         ; save interleave factor
        move.w  0x1a(A7),virgin(A4)          ; save initial sector data

;--- put drive into "changed" mode
;       moveq   #m_changed,D0           ; D0 = "CHANGED"
;       bsr     setdmode                ; set media change mode

;--- seek to track (hard seek):
;debug* move.l  #0xff00ff00,0xf8030
        bsr     hseek                   ; hard seek to 'ctrack'
;debug* move.l  #0x00000000,0xf8030
        bne     flopfail                ; (return error on seek failure)
        move.w  ctrack(A4),dcurtrack(A1)    ; record current track#

;--- format track, then verify it:
;*      move.w  #e_error,curr_err(A4)(A5)   ; vanilla error mode
;debug* move.l  #0xff00ff00,0xfA030
        bsr     fmtrack                 ; format track
;debug* move.l  #0x0,0xfA030

        bne     flopfail                ; (return error on seek failure)
        bra     flopok


;****************************
;+
; fmtrack - format a track. Tweaked for skewed interleave.
;
; Passed:       variables setup by _flopfmt
; Returns:      NE on failure, EQ on success
; Uses:         almost everything
; Called-by:    _flopfmt
;
;-
fmtrack:
;*      move.w  #e_write,def_error(A4)  ; set default error number
        move.w  #1,D3                   ; start with sector 1, first pass
;**
        movea.l  cdma(A4),A2            ; A2 =  prototyping area
; Lay down beginning of track

        move.w  #60-1,D1                ; 60 x 0x4e (track leadin)
        move.b  #0x4e,D0
        bsr     wmult
; Repeat 10 times: sector data.
        move.w  #1,sectorno(A4)             ; how many secs written
; Note that twistsectorno is initialized out of this routine.
;--- address mark
secloop: nop
;
ot1:    move.w  #12-1,D1                ; 12 x 0x00
        clr.b   D0
        bsr     wmult
        move.w  #3-1,D1                 ; 3 x 0xf5
        move.b  #0xf5,D0
        bsr     wmult
        move.b  #0xfe,(A2)+              ; 0xfe -- address mark intro
        move.b  ctrack+1(A4),(A2)+          ; track# - low half of word
        move.b  cside+1(A4),(A2)+           ; side# - low half of word

;* #1: just use a plain sector number
;*      move.b  D4,(A2)+                ; sector#

;* #2: use a twisted sector number
;*      move.b  twistsectorno+1(A4),(A2)+   ; new: sector #.

        move.w  twistsectorno(A4),D0        ; fetch     1-10 sector #
;
; Note that meg-a-minute backup uses sectors # 11-20 to force GEM
; not to use MM disks.
;
        add.w   sectoroffset(A4),D0     ; add possible shift to 11-20 sector #
        move.b  D0,(A2)+                ; plug it into sector table

; Add 1 to sector #. If it is b, wrap it to 1.
        addi.w  #1,twistsectorno(A4)        ; real sector # being plopped
        cmpi.w  #0xb,twistsectorno(A4)
        bne     notb
        move.w  #1,twistsectorno(A4)
;
notb:   nop
        move.b  #0x02,(A2)+              ; sector size (512)
        move.b  #0xf7,(A2)+              ; write checksum

;--- gap between AM and data:
        move.w  #22-1,D1                ; 22 x 0x4e
        move.b  #0x4e,D0
        bsr     wmult
        move.w  #12-1,D1                ; 12 x 0x00
        clr.b   D0
        bsr     wmult
        move.w  #3-1,D1                 ; 3 x 0xf5
        move.b  #0xf5,D0
        bsr     wmult

;--- data block:
        move.b  #0xfb,(A2)+              ; 0xfb -- data intro
        move.w  #256-1,D1               ; 256 x virgin.w (initial sector data)
ot2:    move.b  virgin(A4),(A2)+            ; copy high byte
        move.b  virgin+1(A4),(A2)+          ; copy low byte
        dbf     D1,ot2                  ; fill 512 bytes
        move.b  #0xf7,(A2)+              ; 0xf7 -- write checksum
        move.w  #40-1,D1                ; 40 x 0x4e
        move.b  #0x4e,D0
        bsr     wmult
;
; Next sector, or, end-of-track. If we hit sector 11, time to quit.
;
        addi.w   #1,sectorno(A4)
        cmpi.w  #11,sectorno(A4)
        bne     secloop         ; loop again
;
; Okay, 10 sectors laid down. 
;
;--- end-of-track
        move.w  #1400,D1                ; 1401 x 0x4e -- end of track trailer
        move.b  #0x4e,D0
        bsr     wmult

;--- setup to write the track:
        move.b  cdma+3(A4),dmalow   ; load dma pointer
        move.b  cdma+2(A4),dmamid
        move.b  cdma+1(A4),dmahigh
        move.w  #0x190,(A6)              ; toggle R/W flag and
        move.w  #0x090,(A6)              ; select sector-count register
        move.w  #0x190,(A6)
        move.w  #0x1f,D7                 ; (absurd sector count)
        bsr     wdiskctl
        move.w  #0x180,(A6)              ; select 1770 cmd register
        move.w  #0xf0,D7                 ; write format_track command
;debug* move.l  #0xff00ff00,0xfc030
        bsr     wdiskctl
        move.l  #timeout,D7             ; D7 = timeout value

;--- wait for 1770 to complete:
otw1:   btst.b  #5,gpip                 ; is 1770 done?
        beq     otw2                    ; (yes)
        subq.l  #1,D7                   ; if(--D7) continue;
        bne     otw1
;debug* move.l  #0xffffffff,0xfc030

        bsr     reset1770               ; timed out -- reset 1770
oterr:  moveq   #1,D7                   ; return NE (error status)
        rts

;--- see if the write-track won:
otw2:   nop
;debug* move.l  #0x0,0xfc030

        move.w  #0x190,(A6)              ; check DMA status bit
        move.w  (A6),D0
        btst    #0,D0                   ; if its zero, there was a DMA error
        beq     oterr                   ; (so return NE)
        move.w  #0x180,(A6)              ; get 1770 status
        bsr     rdiskctl
;**     bsr     err_bits                ; set 1770 error bits
        and.b   #0x44,D0                 ; check for writeProtect & lostData
        rts                             ; return NE on 1770 error

;------ write 'D1+1' copies of D0.B into A2, A2+1, ...
wmult:  move.b  D0,(A2)+                ; record byte in proto buffer
        dbf     D1,wmult                ; (do it again)
        rts
;
;************************************************************
;
; floplock - lock floppies and setup floppy parameters
;
; Passed (on the stack):
;       0x18(A7) - count.W (sector count)
;       0x16(A7) - side.W (side#)
;       0x14(A7) - track.W (track#)
;       0x12(A7) - sect.W (sector#)
;       0x10(A7) - dev.W (device#)
;        0xc(A7) - obsolete.L
;         8(A7) - dma.L (dma pointer)
;         4(A7) - ret1.L (caller's return address)
;         0(A7) - ret.L (floplock's return address)
;
; It is not coincidence that this matches the read and write input list;
; they call us to get stuff off stack and plug into parameters. Then,
; routine "select" actually pops this stuff into hardware.
;
; Passed:       D0.W = default error number
;
; Also, we helpfully point A6 at the DMA chip, and A1 at the DSB.
;-
floplock:
        lea    regsave, A0
        movem.l D3-D7/A3-A6, (A0)       ; save C registers
        lea     fifo,A6                 ; A6 -> fifo
; Start setting up param block..
        move.w  D0,def_error(A4)            ; set default error number
        move.w  D0,curr_err(A4)             ; set current error number
; Kick VBL off floppies..
        move.w  #1,flock                ; tell vbl not to touch floppies
; Stuff off stack:
        move.l  8(A7),cdma(A4)              ; cdma -> /even/ DMA address
        move.w  0x10(A7),cdev(A4)    ; save device# (0 .. 1)
        move.w  0x12(A7),csect(A4)   ; save sector# (1 .. 9, usually)
        move.w  0x14(A7),ctrack(A4)  ; save track# (0 .. 39 .. 79 ..)
        move.w  0x16(A7),cside(A4)   ; save side# (0 .. 1)
        move.w  0x18(A7),ccount(A4)  ; save sector count (1..A)
;--- pick a DSB: Point A1 at it.
; we need to check which ROMs also, if old use that
; otherwise assume it is a new machine
        lea     dsb0new,A1         ; pick dsb 0 (drive A)
        cmpi.l  #old_rom, rom_date
        bne     rom1
        lea	dsb0old,A1
rom1:   tst.w   cdev(A4)
        beq     flock2
        lea     dsb1new,A1         ; pick dsb 1 (drive B)
        cmpi.l  #old_rom, rom_date
        bne     flock2
        lea     dsb1old,A1
;--- compute ending DMA address from count parameter: Plug into edma.
; This is used in multisector transfers in read-multiple-sector,
; but we don't use it here.
flock2: moveq   #0,D7
        move.w  ccount(A4),D7               ; edma = cdma + (ccount * 512)
        lsl.w   #8,D7
        lsl.w   #1,D7                   ; do a 9 shift..
        movea.l  cdma(A4),A0
        adda.l   D7,A0
        move.l  A0,edma(A4)                 ; save in edma
;--- recalibrate drive, if it needs it. This only happens when the DSB
; says that this drive has never awoken before, and needs an initial
; recal to match its current track # with the DSB track #. 
        tst.w   dcurtrack(A1)           ; if (curtrack < 0) recalibrate()
        bpl     flockr
; RECAL needed. Show flag about it..
        move.l  #0xf0f0f0f0,0xfe000
        move.l  #0xf0f0f0f0,0xfe004

        bsr     select                  ; select drive & side
        clr.w   dcurtrack(A1)           ; we're optimistic -- assume winnage
; Restore.
        bsr     restore                 ; attempt restore
        beq     flockr                  ; (it won)
        moveq   #10,D7                  ; attempt seek to track 10
        bsr     hseek1
        bne     flock1                  ; (failed)
        bsr     restore                 ; attempt restore again
        beq     flockr                  ; (it won)
;
flock1:  move.w  #recal, dcurtrack(A1)    ; complete failure (what can we do?)

        movem.l regsave(PC), D3-D7/A3-A6
flockr: rts
;
;********************************************************************
;+
; flopfail - unlock floppies and return error.
; Common way for read and write to return.
;
; Note: Returns via unlok1.
;-
flopfail:
        move.l  #0xffffffff,D0           ; aargh, error
        bra.s   unlok1                  ; clobber floppy lock & return
;***************************************************
;+
; flopok - unlock floppies and return success status. Also a common
; way for r/w to return.
;
;-
flopok: clr.l   D0                      ; return 0 (success)
; Entry point from flopfail..
unlok1: move.l  D0,-(A7)                ; (save return value)
; I believe this code returns the FDC's status to a type-1 status, where
; the write protect switch is available for VBL to look at.
        move.w  #datareg,(A6)           ; force WP to real-time mode
; Sets FDC's current track register to track we are on right now.
        move.w  dcurtrack(A1),D7        ; dest-track = current track
        bsr     wdiskctl
; Does it with a "noop seek" (source=dest). Only forces FDC to type 1 status.
        move.w  #0x10,D6                 ; cmd = seek w/o verify
        bsr     flopcmds                ; do it
;
unlok2: move.l  (A7)+,D0                ; restore return value
        movem.l  regsave(PC), D3-D7/A3-A6
; clear floppy lock of vblank..
        clr.w   flock                   ; allow vblank .. unlock floppies
; wave byebye at the pretty camera, jenny...
        rts
;************************ Seek routines ********************
;+
; hseek  - seek to 'ctrack(A4)' without verify
; hseek1 - seek to 'D7' without verify
; hseek2 - seek to 'D7' without verify, keep current error number
;
; Returns:      NE on seek failure ("cannot happen"?)
;               EQ if seek wins
;
; Uses:         D7, D6, ...
; Exits to:     flopcmds
; Called-by:    _flopfmt, _flopini
;
;-
hseek:  move.w  ctrack(A4),D7               ; dest track = 'ctrack'
hseek1: nop
hseek2: move.w  #datareg,(A6)           ; write destination track# to data reg
        bsr     wdiskctl                ; write D7 to FDC data register
; seek command:
        move.w  #0x10,D6                 ; execute "seek" command
;                                       * Note: no spinup time.
        bra     flopcmds                ; (without verify...)
;
;***********************************************
;+
; reseek - home head, then reseek track
; Returns:      EQ/NE on success/failure
; Falls-into:   go2track
;
;-
reseek:
        bsr     restore                 ; restore head
        bne     go2trr                  ; (punt if home fails)

        clr.w   dcurtrack(A1)           ; current track = 0
        move.w  #trkreg,(A6)            ; set "current track" reg on 1770
        clr.w   D7
        bsr     wdiskctl                ; write a 00 to trk register.

        move.w  #datareg,(A6)           ; seek out to track five
        move.w  #5,D7
        bsr     wdiskctl                ; dest track = 5
        move.w  #0x10,D6
        bsr     flopcmds                ; seek
;                                       * Note: no spinup time.
        bne     go2trr                  ; return error on seek failure
        move.w  #5,dcurtrack(A1)        ; set current track#

;***********************************************+
; go2track - seek proper track
; Passed:       Current floppy parameters (ctrack, et al.).
; Returns:      EQ/NE on success/failure
; Calls:        flopcmds
; Called by: read sector, for instance. Lots of places.
;-
go2track:
        move.w  #datareg,(A6)           ; set destination track# in
        move.w  ctrack(A4),D7               ;  1770's data register
        bsr     wdiskctl                ; (write track#)
        moveq   #0x14,D6                 ; execute 1770 "seek_with_verify"
        bsr     flopcmds                ; (include seek-rate bits)
        bne     go2trr                  ; return error on seek failure
        move.w  ctrack(A4),dcurtrack(A1)    ; update current track number
        and.b   #0x18,D7                 ; check for RNF, CRC_error, lost_data
go2trr: rts                             ; return EQ/NE on succes/failure

;*************************************************
;+
; restore - home head
; Passed:       nothing
; Returns:      EQ/NE on success/failure
;-
restore:
        clr.w   D6                      ; 0x00 = 1770 "restore" command
        bsr     flopcmds                ; do restore
        bne     res_r                   ; punt on timeout
        btst    #2,D7                   ; test TRK00 bit
        eori.w  #0x04, CCR              ; flip Z bit (return NE if bit is zero)
        bne     res_r                   ; punt if didn't win
        clr.w   dcurtrack(A1)           ; set current track#
res_r:  rts

;****************************************************
; Special floppy cmd just for seeking:
;+
; flopcmds - floppy command (or-in seek speed bits from database)
; Passed:       D6.w = 1770 command
; Sets-up:      seek bits (bits 0 and 1) in D6.w
; Falls-into:   flopcmd
; Returns:      EQ/NE on success/failure
;
; I get the impression this is only used for seeking. I am right.
;-
flopcmds:
        move.w  dseekrt(A1),D0          ; get floppy's seek rate bits
        andi.b  #3,D0                   ; OR into command
        or.b    D0,D6
; Fall in...
;******************************************************+
; flopcmd - execute any ol' 1770 command (with timeout)
; Passed:       D6.w = 1770 command
;
; Returns:      EQ/NE on success/failure
;               D7 = 1770 status bits
;
; Note: does motor spinup, if cmd in D6 specs it (I would *hope*!)
;-
flopcmd:
        move.l  #timeout,D7             ; setup timeout count (assume short)
        move.w  #cmdreg,(A6)            ; select 1770 command register
        bsr     rdiskctl                ; read it to clobber READY status
        btst    #7,D0                   ; is motor on?
        bne     flopcm                  ; (yes, keep short timeout)
        move.l  #ltimeout,D7            ; extra timeout for motor startup
flopcm: bsr     wdiskct6                ; write command (in D6)

flopc1: subq.l  #1,D7                   ; timeout?
        beq     flopcto                 ; (yes, reset and return failure)
        btst.b  #5,gpip                 ; 1770 completion?
        bne     flopc1                  ; (not yet, so wait some more)
        bsr     rdiskct7                ; return EQ + 1770 status in D7
        clr.w   D6
        rts
;****
flopcto:
; We timed out.. a gruesome death indeed.
; Whap controller back to life.    (Hit him harder Dave, he likes it that way)
        bsr     reset1770               ; bash controller
        moveq   #1,D6                   ; and return NE
        rts

;*******************************************************
;+
; reset1770 - reset disk controller after a catastrophe
; Passed:       nothing
; Returns:      nothing
; Uses:         D7
;-
reset1770:
        move.w  #cmdreg,(A6)            ; execute 1770 "reset" command
        move.w  #0xD0,D7                 ; force interrupt
        bsr     wdiskctl
        move.w  #15,D7                  ; wait for 1770 to stop convulsing
r1770:  dbf     D7,r1770                ; (short delay loop)
        bsr     rdiskct7                ; return 1770 status in D7
        rts

;******************************************************
;+
; select - setup drive select, 1770 and DMA registers
; Passed:       cside(A4), cdev(A4)
; Returns:      appropriate drive and side selected
;
; Called: All over the place.
;
;-
select: move.w  #0,0x9c0                 ; floppies NOT deselected
;                                       * lets VBL shut them off...
        move.w  cdev(A4),D0                 ; get device number
        addq.b  #1,D0                   ; add and shift to get select bits
        lsl.b   #1,D0                   ; into bits 1 and 2
        or.w    cside(A4),D0                ; or-in side number (bit 0)
        eori.b   #7,D0                   ; negate bits for funky hardware select
        andi.b   #7,D0                   ; strip anything else out there
        bsr     setporta                ; do drive select
; Have to restore 1770's track register from table..in dsb.
        move.w  #trkreg,(A6)            ; setup 1770 track register
        move.w  dcurtrack(A1),D7        ; from current track number
        bsr     wdiskctl
        clr.b   tmpdma(A4)                  ; zero bits 24..32 of target DMA addr

; Setup R/W parameters on 1770. Used by
; r/w sector, among others. This is where the sector register gets set.
; 
select1:
        move.w  #secreg,(A6)            ; setup requested sector_number from
        move.w  csect(A4),D7                ;       caller's parameters
        bsr     wdiskctl
        move.b  cdma+3(A4),dmalow           ; setup DMA chip's DMA pointer
        move.b  cdma+2(A4),dmamid
        move.b  cdma+1(A4),dmahigh
        rts

;************************************************
;+
; setporta - set floppy select bits in PORT A on the sound chip
; Passed:       D0.b (low three bits)
; Returns:      D1 = value written to port A
;               D2 = old value read from port A
; Uses:         D1
;-
setporta:
        move    SR,-(A7)                ; save our IPL
        ori     #0x0700,SR               ; start critical section
        move.b  #giporta,giselect       ; select port on GI chip
        move.b  giread,D1               ; get current bits
        move.b  D1,D2                   ; save old bits for caller
        andi.b   #0xff-7,D1               ; strip low three bits there
        or.b    D0,D1                   ; or-in our new bits
        move.b  D1,giwrite              ; and write 'em back out there
        move    (A7)+,SR                ; restore IPL to terminate CS, return
        rts

;**************************************************
;+
; Primitives to read/write 1770 controller chip (DISKCTL register).
;
; The 1770 can't keep up with full-tilt CPU accesses, so
; we have to surround reads and writes with delay loops.
; This is not really as slow as it sounds.
;
wdiskct6:                               ; write D6 to diskctl
        bsr     rwdelay                 ;       delay
        move.w  D6,diskctl              ;       write it
        bra     rwdelay                 ;       delay and return

wdiskctl:                               ; write D7 to diskctl
        bsr     rwdelay                 ;       delay
        move.w  D7,diskctl              ;       write it
        bra     rwdelay                 ;       delay and return

rdiskct7:                               ; read diskctl into D7
        bsr     rwdelay                 ;       delay
        move.w  diskctl,D7              ;       read it
        bra     rwdelay                 ;       delay and return

rdiskctl:                               ; read diskctl into D0
        bsr     rwdelay                 ;       delay
        move.w  diskctl,D0              ;       read it
; And here's the delay loop:
rwdelay:
        move    SR,-(A7)                ; save flags
        move.w  D7,-(A7)                ; save counter register
        move.w  #0x20,D7                ; 0x20 seems about right...
rwdly1: dbf     D7,rwdly1               ; busy-loop: give 1770 time to settle
        move.w  (A7)+,D7                ; restore register, flags, and return
        move    (A7)+,SR
        rts

;-------------------------------------
regsave:  dc.l      1      ; PC relative data area
          dc.l      2
          dc.l      3
          dc.l      4
          dc.l      5
          dc.l      6
          dc.l      7
          dc.l      8
          dc.l      9


}         /* MY GOD!  It's DONE!  */
