Home | History | Annotate | Line # | Download | only in obio
iwm.s revision 1.3
      1  1.3     chs /*	$NetBSD: iwm.s,v 1.3 2001/11/20 03:19:44 chs Exp $	*/
      2  1.1  scottr 
      3  1.1  scottr /*
      4  1.2  scottr  * Copyright (c) 1996-99 Hauke Fath.  All rights reserved.
      5  1.1  scottr  *
      6  1.1  scottr  * Redistribution and use in source and binary forms, with or without
      7  1.1  scottr  * modification, are permitted provided that the following conditions
      8  1.1  scottr  * are met:
      9  1.1  scottr  * 1. Redistributions of source code must retain the above copyright
     10  1.1  scottr  *    notice, this list of conditions and the following disclaimer.
     11  1.1  scottr  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  scottr  *    notice, this list of conditions and the following disclaimer in the
     13  1.1  scottr  *    documentation and/or other materials provided with the distribution.
     14  1.1  scottr  * 3. The name of the author may not be used to endorse or promote products
     15  1.1  scottr  *    derived from this software without specific prior written permission.
     16  1.1  scottr  *
     17  1.1  scottr  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  1.1  scottr  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  1.1  scottr  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  1.1  scottr  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  1.1  scottr  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  1.1  scottr  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  1.1  scottr  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  1.1  scottr  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  1.1  scottr  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  1.1  scottr  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  1.1  scottr  */
     28  1.1  scottr 
     29  1.1  scottr /*
     30  1.1  scottr  * iwm.s -- low level routines for Sony floppy disk access.
     31  1.1  scottr  * The present implementation supports the 800K GCR format on non-DMA
     32  1.1  scottr  * machines.
     33  1.1  scottr  *
     34  1.1  scottr  * The IWM and SWIM chips run in polled mode; they are not capable of
     35  1.1  scottr  * interrupting the CPU. That's why interrupts need only be blocked
     36  1.1  scottr  * when there is simply no time for interrupt routine processing,
     37  1.1  scottr  * i.e. during data transfers.
     38  1.1  scottr  *
     39  1.1  scottr  * o  The local routines do not block any interrupts.
     40  1.1  scottr  *
     41  1.1  scottr  * o  The iwmXXX() routines that set/get IWM or drive settings are not
     42  1.1  scottr  *    time critical and do not block interrupts.
     43  1.1  scottr  *
     44  1.1  scottr  * o  The iwmXXX() routines that are called to perform data transfers
     45  1.1  scottr  *    block all interrupts because otherwise the current sector data
     46  1.1  scottr  *    would be lost.
     47  1.1  scottr  *    The old status register content is stored on the stack.
     48  1.1  scottr  *
     49  1.2  scottr  * o  We run at spl4 to give the NMI switch a chance. All currently
     50  1.2  scottr  *    supported machines have no interrupt sources > 4 (SSC) -- the
     51  1.2  scottr  *    Q700 interrupt levels can be shifted around in A/UX mode,
     52  1.2  scottr  *    but we're not there, yet.
     53  1.2  scottr  *
     54  1.1  scottr  * o  As a special case iwmReadSectHdr() must run with interrupts disabled
     55  1.1  scottr  *    (it transfers data). Depending on the needs of the caller, it
     56  1.1  scottr  *    may be necessary to block interrupts after completion of the routine
     57  1.1  scottr  *    so interrupt handling is left to the caller.
     58  1.1  scottr  *
     59  1.1  scottr  * If we wanted to deal with incoming serial data / serial interrupts,
     60  1.1  scottr  * we would have to either call zshard(0) {mac68k/dev/zs.c} or
     61  1.1  scottr  * zsc_intr_hard(0) {sys/dev/ic/z8530sc.c}. Or we would have to roll our
     62  1.1  scottr  * own as both of the listed function calls look rather expensive compared
     63  1.1  scottr  * to a 'tst.b REGADDR ; bne NN'.
     64  1.1  scottr  */
     65  1.1  scottr 
     66  1.1  scottr #include <m68k/asm.h>
     67  1.1  scottr 
     68  1.2  scottr #include <mac68k/obio/iwmreg.h>
     69  1.1  scottr 
     70  1.1  scottr #define USE_DELAY	0	/* "1" bombs for unknown reasons */
     71  1.1  scottr 
     72  1.1  scottr 
     73  1.1  scottr /*
     74  1.1  scottr  * References to global name space
     75  1.1  scottr  */
     76  1.3     chs 	.extern	_C_LABEL(TimeDBRA)	| in mac68k/macrom.c
     77  1.3     chs 	.extern _C_LABEL(Via1Base)	| in mac68k/machdep.c
     78  1.3     chs 	.extern	_C_LABEL(IWMBase)	| in iwm_fd.c
     79  1.1  scottr 
     80  1.1  scottr 
     81  1.1  scottr 	.data
     82  1.1  scottr 
     83  1.1  scottr diskTo:
     84  1.1  scottr 	/*
     85  1.1  scottr 	 * Translation table from 'disk bytes' to 6 bit 'nibbles',
     86  1.1  scottr 	 * taken from the .Sony driver.
     87  1.1  scottr 	 * This could be made a loadable table (via ioctls) to read
     88  1.1  scottr 	 * e.g. ProDOS disks (there is a hook for such a table in .Sony).
     89  1.1  scottr 	 */
     90  1.1  scottr 	.byte	/* 90 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01
     91  1.1  scottr 	.byte	/* 98 */  0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, 0x05, 0x06
     92  1.1  scottr 	.byte	/* A0 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x08
     93  1.1  scottr 	.byte	/* A8 */  0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, 0x0C, 0x0D
     94  1.1  scottr 	.byte	/* B0 */  0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13
     95  1.1  scottr 	.byte	/* B8 */  0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A
     96  1.1  scottr 	.byte	/* C0 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
     97  1.1  scottr 	.byte	/* C8 */  0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, 0x1D, 0x1E
     98  1.1  scottr 	.byte	/* D0 */  0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x20, 0x21
     99  1.1  scottr 	.byte	/* D8 */  0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28
    100  1.1  scottr 	.byte	/* E0 */  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, 0x2A, 0x2B
    101  1.1  scottr 	.byte	/* E8 */  0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32
    102  1.1  scottr 	.byte	/* F0 */  0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38
    103  1.1  scottr 	.byte	/* F8 */  0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F
    104  1.1  scottr 
    105  1.1  scottr hdrLeadIn:
    106  1.1  scottr 	.byte	0xD5, 0xAA, 0x96
    107  1.1  scottr 
    108  1.1  scottr hdrLeadOut:
    109  1.1  scottr 	.byte	0xDE, 0xAA, 0xFF
    110  1.1  scottr 
    111  1.1  scottr dataLeadIn:
    112  1.1  scottr 	.byte	0xD5, 0xAA, 0xAD
    113  1.1  scottr 
    114  1.1  scottr dataLeadOut:
    115  1.1  scottr 	.byte	0xDE, 0xAA, 0xFF, 0xFF
    116  1.1  scottr 
    117  1.1  scottr 
    118  1.1  scottr toDisk:
    119  1.1  scottr 	/*
    120  1.1  scottr 	 * Translation table from 6-bit nibbles [0x00..0x3f] to 'disk bytes'
    121  1.1  scottr 	 */
    122  1.1  scottr 	.byte	/* 00 */  0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6
    123  1.1  scottr 	.byte	/* 08 */  0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3
    124  1.1  scottr 	.byte	/* 10 */  0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC
    125  1.1  scottr 	.byte	/* 18 */  0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3
    126  1.1  scottr 	.byte	/* 20 */  0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE
    127  1.1  scottr 	.byte	/* 28 */  0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC
    128  1.1  scottr 	.byte	/* 30 */  0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xf5, 0xF6
    129  1.1  scottr 	.byte	/* 38 */  0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
    130  1.1  scottr 
    131  1.1  scottr syncPattern:
    132  1.1  scottr 	/*
    133  1.1  scottr 	 * This sync pattern creates 4 sync chars with 10 bits each that look
    134  1.1  scottr 	 * like 0011111111b (i.e. 0x0FF). As the IWM ignores leading zero
    135  1.1  scottr 	 * bits, it locks on 0xFF after the third sync byte.
    136  1.1  scottr 	 * For convenience, the bytes of the sector data lead-in
    137  1.1  scottr 	 * (D5 AA AD) follow.
    138  1.1  scottr 	 */
    139  1.1  scottr 	.byte	0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF
    140  1.1  scottr 	.byte	0xD5, 0xAA, 0xAD
    141  1.1  scottr 
    142  1.1  scottr 
    143  1.1  scottr 
    144  1.1  scottr 	.text
    145  1.1  scottr 
    146  1.1  scottr /*
    147  1.1  scottr  * Register conventions:
    148  1.3     chs  *	%a0	IWM base address
    149  1.3     chs  *	%a1	VIA1 base address
    150  1.1  scottr  *
    151  1.3     chs  *	%d0	return value (0 == no error)
    152  1.1  scottr  *
    153  1.1  scottr  * Upper bits in data registers that are not cleared give nasty
    154  1.1  scottr  * (pseudo-) random errors when building an address. Make sure those
    155  1.1  scottr  *  registers are cleaned with a moveq before use!
    156  1.1  scottr  */
    157  1.1  scottr 
    158  1.1  scottr 
    159  1.1  scottr 
    160  1.1  scottr /**
    161  1.1  scottr  **	Export wrappers
    162  1.1  scottr  **/
    163  1.1  scottr 
    164  1.1  scottr /*
    165  1.1  scottr  * iwmQueryDrvFlags -- export wrapper for driveStat
    166  1.1  scottr  *
    167  1.1  scottr  * Parameters:	stack	l	drive selector
    168  1.1  scottr  *		stack	l	register selector
    169  1.3     chs  * Returns:	%d0		flag
    170  1.1  scottr  */
    171  1.1  scottr ENTRY(iwmQueryDrvFlag)
    172  1.3     chs 	link	%a6,#0
    173  1.3     chs 	moveml	%d1/%a0-%a1,%sp@-
    174  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    175  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    176  1.1  scottr 
    177  1.3     chs 	movel	%a6@(8),%d0		| Get drive #
    178  1.1  scottr 	beq	quDrv00
    179  1.3     chs 	cmpl	#1,%d0
    180  1.1  scottr 	beq	quDrv01
    181  1.1  scottr 
    182  1.1  scottr 	bra	quDone			| Invalid drive #
    183  1.1  scottr 
    184  1.1  scottr quDrv00:
    185  1.3     chs 	tstb	%a0@(intDrive)		| SELECT; choose drive #0
    186  1.1  scottr 	bra	queryDrv
    187  1.1  scottr 
    188  1.1  scottr quDrv01:
    189  1.3     chs 	tstb	%a0@(extDrive)		| SELECT; choose drive #1
    190  1.1  scottr 
    191  1.1  scottr queryDrv:
    192  1.3     chs 	movel	%a6@(12),%d0		| Get register #
    193  1.1  scottr 	bsr	driveStat
    194  1.1  scottr 
    195  1.1  scottr quDone:
    196  1.3     chs 	moveml	%sp@+,%d1/%a0-%a1
    197  1.3     chs 	unlk	%a6
    198  1.1  scottr 	rts
    199  1.1  scottr 
    200  1.1  scottr 
    201  1.1  scottr /*
    202  1.1  scottr  * iwmReadSectHdr -- read and decode the next available sector header.
    203  1.1  scottr  *
    204  1.1  scottr  * Parameters:	stack	l	Address of sector header struct (I/O)
    205  1.1  scottr  *				b	side (0, 1)
    206  1.1  scottr  *				b	track (0..79)
    207  1.1  scottr  *				b	sector (0..11)
    208  1.3     chs  * Returns:	%d0		result code
    209  1.1  scottr  */
    210  1.1  scottr ENTRY(iwmReadSectHdr)
    211  1.3     chs 	link	%a6,#0
    212  1.3     chs 	moveml	%d1-%d5/%a0-%a4,%sp@-
    213  1.3     chs 	movel	%a6@(0x08),%a4		| Get param block address
    214  1.1  scottr 	bsr	readSectHdr
    215  1.3     chs 	moveml	%sp@+,%d1-%d5/%a0-%a4
    216  1.3     chs 	unlk	%a6
    217  1.1  scottr 	rts
    218  1.1  scottr 
    219  1.1  scottr 
    220  1.1  scottr 
    221  1.1  scottr /**
    222  1.1  scottr  **	Exported functions
    223  1.1  scottr  **/
    224  1.1  scottr 
    225  1.1  scottr /*
    226  1.1  scottr  * iwmInit -- Initialize IWM chip.
    227  1.1  scottr  *
    228  1.1  scottr  * Parameters:	-
    229  1.3     chs  * Returns:	%d0		result code
    230  1.1  scottr  */
    231  1.1  scottr ENTRY(iwmInit)
    232  1.3     chs 	link	%a6,#0
    233  1.3     chs 	moveml	%d2/%a0,%sp@-
    234  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    235  1.1  scottr 
    236  1.1  scottr 	/*
    237  1.1  scottr 	 * Reset IWM to known state (clear disk I/O latches)
    238  1.1  scottr 	 */
    239  1.3     chs 	tstb	%a0@(ph0L)		| CA0
    240  1.3     chs 	tstb	%a0@(ph1L)		| CA1
    241  1.3     chs 	tstb	%a0@(ph2L)		| CA2
    242  1.3     chs 	tstb	%a0@(ph3L)		| LSTRB
    243  1.3     chs 
    244  1.3     chs 	tstb	%a0@(mtrOff)		| ENABLE; make sure drive is off
    245  1.3     chs 	tstb	%a0@(intDrive)		| SELECT; choose drive 1
    246  1.3     chs 	moveq	#0x1F,%d0		| XXX was 0x17 -- WHY!?
    247  1.1  scottr 
    248  1.1  scottr 	/*
    249  1.1  scottr 	 * First do it quick...
    250  1.1  scottr 	 */
    251  1.3     chs 	tstb	%a0@(q6H)
    252  1.3     chs 	andb	%a0@(q7L),%d0		| status register
    253  1.3     chs 	tstb	%a0@(q6L)
    254  1.3     chs 	cmpib	#iwmMode,%d0		| all is well??
    255  1.1  scottr 	beq	initDone
    256  1.1  scottr 
    257  1.1  scottr 	/*
    258  1.1  scottr 	 * If this doesn't succeed (e.g. drive still running),
    259  1.1  scottr 	 * we do it thoroughly.
    260  1.1  scottr 	 */
    261  1.3     chs 	movel	#0x00080000,%d2		| ca. 500,000 retries = 1.5 sec
    262  1.1  scottr initLp:
    263  1.3     chs 	moveq	#initIWMErr,%d0		| Initialization error
    264  1.3     chs 	subql	#1,%d2
    265  1.1  scottr 	bmi	initErr
    266  1.3     chs 	tstb	%a0@(mtrOff)		| disable drive
    267  1.3     chs 	tstb	%a0@(q6H)
    268  1.3     chs 	moveq	#0x3F,%d0
    269  1.3     chs 	andb	%a0@(q7L),%d0
    270  1.3     chs 	bclr	#5,%d0			| Reset bit 5 and set Z flag
    271  1.1  scottr 					| according to previous state
    272  1.1  scottr 	bne	initLp			| Loop if drive still on
    273  1.3     chs 	cmpib	#iwmMode,%d0
    274  1.1  scottr 	beq	initDone
    275  1.3     chs 	moveb	#iwmMode,%a0@(q7H)	| Init IWM
    276  1.3     chs 	tstb	%a0@(q7L)
    277  1.1  scottr 	bra	initLp
    278  1.1  scottr 
    279  1.1  scottr initDone:
    280  1.3     chs 	tstb	%a0@(q6L)		| Prepare IWM for data
    281  1.3     chs 	moveq	#0,%d0			| noErr
    282  1.1  scottr 
    283  1.1  scottr initErr:
    284  1.3     chs 	moveml	%sp@+,%d2/%a0
    285  1.3     chs 	unlk	%a6
    286  1.1  scottr 	rts
    287  1.1  scottr 
    288  1.1  scottr 
    289  1.1  scottr /*
    290  1.1  scottr  * iwmCheckDrive -- Check if given drive is available and return bit vector
    291  1.1  scottr  *	with capabilities (SS/DS, disk inserted, ...)
    292  1.1  scottr  *
    293  1.1  scottr  * Parameters:	stack	l	Drive number (0,1)
    294  1.3     chs  * Returns:	%d0	Bit	 0 - 0 = Drive is single sided
    295  1.1  scottr  *				 1 - 0 = Disk inserted
    296  1.1  scottr  *				 2 - 0 = Motor is running
    297  1.1  scottr  *				 3 - 0 = Disk is write protected
    298  1.1  scottr  *				 4 - 0 = Disk is DD
    299  1.1  scottr  *				31 - (-1) No drive / invalid drive #
    300  1.1  scottr  */
    301  1.1  scottr ENTRY(iwmCheckDrive)
    302  1.3     chs 	link	%a6,#0
    303  1.3     chs 	moveml	%d1/%a0-%a1,%sp@-
    304  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    305  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    306  1.1  scottr 
    307  1.3     chs 	moveq	#-1,%d1			| no drive
    308  1.1  scottr 
    309  1.3     chs 	movel	%a6@(0x08),%d0		| check drive #
    310  1.1  scottr 	beq	chkDrv00
    311  1.3     chs 	cmpl	#1,%d0
    312  1.1  scottr 	beq	chkDrv01
    313  1.1  scottr 
    314  1.1  scottr 	bra	chkDone			| invalid drive #
    315  1.1  scottr 
    316  1.1  scottr chkDrv00:
    317  1.3     chs 	tstb	%a0@(intDrive)		| SELECT; choose drive #0
    318  1.1  scottr 	bra	chkDrive
    319  1.1  scottr 
    320  1.1  scottr chkDrv01:
    321  1.3     chs 	tstb	%a0@(extDrive)		| SELECT; choose drive #1
    322  1.1  scottr 
    323  1.1  scottr chkDrive:
    324  1.3     chs 	moveq	#-2,%d1			| error code
    325  1.3     chs 	moveq	#drvInstalled,%d0	| Drive installed?
    326  1.1  scottr 	bsr	driveStat
    327  1.1  scottr 	bmi	chkDone			| no drive
    328  1.1  scottr 
    329  1.3     chs 	moveq	#0,%d1			| Drive found
    330  1.3     chs 	tstb	%a0@(mtrOn)		| ENABLE; activate drive
    331  1.3     chs 	moveq	#singleSided,%d0	| Drive is single-sided?
    332  1.1  scottr 	bsr	driveStat
    333  1.1  scottr 	bpl	chkHasDisk
    334  1.1  scottr 	/*
    335  1.1  scottr 	 * Drive is double-sided -- this is not really a surprise as the
    336  1.1  scottr 	 * old ss 400k drive needs disk speed control from the Macintosh
    337  1.1  scottr 	 * and we're not doing that here. Anyway - just in case...
    338  1.1  scottr 	 * I am not sure m680x0 Macintoshes (x>0) support 400K drives at all
    339  1.1  scottr 	 * due to their radically different sound support.
    340  1.1  scottr 	 */
    341  1.3     chs 	bset	#0,%d1			| 1 = no.
    342  1.1  scottr chkHasDisk:
    343  1.3     chs 	moveq	#diskInserted,%d0	| Disk inserted?
    344  1.1  scottr 	bsr	driveStat
    345  1.1  scottr 	bpl	chkMotorOn
    346  1.3     chs 	bset	#1,%d1			| 1 = No.
    347  1.1  scottr 	bra	chkDone
    348  1.1  scottr chkMotorOn:
    349  1.3     chs 	moveq	#drvMotorState,%d0	| Motor is running?
    350  1.1  scottr 	bsr	driveStat
    351  1.1  scottr 	bpl	chkWrtProt
    352  1.3     chs 	bset	#2,%d1			| 1 = No.
    353  1.1  scottr chkWrtProt:
    354  1.3     chs 	moveq	#writeProtected,%d0	| Disk is write protected?
    355  1.1  scottr 	bsr	driveStat
    356  1.1  scottr 	bpl	chkDD_HD
    357  1.3     chs 	bset	#3,%d1			| 1 = No.
    358  1.1  scottr chkDD_HD:
    359  1.3     chs 	moveq	#diskIsHD,%d0		| Disk is HD? (was "drive installed")
    360  1.1  scottr 	bsr	driveStat
    361  1.1  scottr 	bpl	chkDone
    362  1.3     chs 	bset	#4,%d1			| 1 = No.
    363  1.1  scottr chkDone:
    364  1.3     chs 	movel	%d1,%d0
    365  1.3     chs 	moveml	%sp@+,%d1/%a0-%a1
    366  1.3     chs 	unlk	%a6
    367  1.1  scottr 	rts
    368  1.1  scottr 
    369  1.1  scottr 
    370  1.1  scottr /*
    371  1.1  scottr  * iwmDiskEject -- post EJECT command and toggle LSTRB line to give a
    372  1.1  scottr  * strobe signal.
    373  1.1  scottr  * IM III says pulse length = 500 ms, but we seem to get away with
    374  1.1  scottr  * less delay; after all, we spin lock the CPU with it.
    375  1.1  scottr  *
    376  1.1  scottr  * Parameters:	stack	l	drive number (0,1)
    377  1.3     chs  *		%a0		IWMBase
    378  1.3     chs  *		%a1		VIABase
    379  1.3     chs  * Returns:	%d0		result code
    380  1.1  scottr  */
    381  1.1  scottr ENTRY(iwmDiskEject)
    382  1.3     chs 	link	%a6,#0
    383  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    384  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    385  1.1  scottr 
    386  1.3     chs 	movel	%a6@(0x08),%d0		| Get drive #
    387  1.1  scottr 	beq	ejDrv00
    388  1.3     chs 	cmpw	#1,%d0
    389  1.1  scottr 	beq	ejDrv01
    390  1.1  scottr 
    391  1.1  scottr 	bra	ejDone			| Invalid drive #
    392  1.1  scottr 
    393  1.1  scottr ejDrv00:
    394  1.3     chs 	tstb	%a0@(intDrive)		| SELECT; choose drive #0
    395  1.1  scottr 	bra	ejDisk
    396  1.1  scottr 
    397  1.1  scottr ejDrv01:
    398  1.3     chs 	tstb	%a0@(extDrive)		| SELECT; choose drive #1
    399  1.1  scottr ejDisk:
    400  1.3     chs 	tstb	%a0@(mtrOn)		| ENABLE; activate drive
    401  1.1  scottr 
    402  1.3     chs 	moveq	#motorOffCmd,%d0	| Motor off
    403  1.1  scottr  	bsr	driveCmd
    404  1.1  scottr 
    405  1.3     chs 	moveq	#diskInserted,%d0	| Disk inserted?
    406  1.1  scottr 	bsr	driveStat
    407  1.1  scottr 	bmi	ejDone
    408  1.1  scottr 
    409  1.3     chs 	moveq	#ejectDiskCmd,%d0	| Eject it
    410  1.1  scottr 	bsr	selDriveReg
    411  1.1  scottr 
    412  1.3     chs 	tstb	%a0@(ph3H)		| LSTRB high
    413  1.1  scottr #if USE_DELAY
    414  1.3     chs 	movel	#1000,%sp@-		| delay 1 ms
    415  1.1  scottr 	jsr	_C_LABEL(delay)
    416  1.3     chs 	addqw	#4,%sp			| clean up stack
    417  1.1  scottr #else
    418  1.3     chs 	movew	#1,%d0
    419  1.1  scottr 	bsr	iwmDelay
    420  1.1  scottr #endif
    421  1.3     chs 	tstb	%a0@(ph3L)		| LSTRB low
    422  1.3     chs 	moveq	#0,%d0			| All's well...
    423  1.1  scottr ejDone:
    424  1.3     chs 	unlk	%a6
    425  1.1  scottr 	rts
    426  1.1  scottr 
    427  1.1  scottr 
    428  1.1  scottr /*
    429  1.1  scottr  * iwmSelectDrive -- select internal (0) / external (1) drive.
    430  1.1  scottr  *
    431  1.1  scottr  * Parameters:	stack	l	drive ID (0/1)
    432  1.3     chs  * Returns:	%d0		drive #
    433  1.1  scottr  */
    434  1.1  scottr ENTRY(iwmSelectDrive)
    435  1.3     chs 	link	%a6,#0
    436  1.3     chs 	moveml	%a0-%a1,%sp@-
    437  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    438  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    439  1.1  scottr 
    440  1.3     chs 	movel	%a6@(8),%d0		| Get drive #
    441  1.1  scottr 	bne	extDrv
    442  1.3     chs 	tstb	%a0@(intDrive)
    443  1.1  scottr 	bra	sdDone
    444  1.1  scottr extDrv:
    445  1.3     chs 	tstb	%a0@(extDrive)
    446  1.1  scottr sdDone:
    447  1.3     chs 	moveml	%sp@+,%a0-%a1
    448  1.3     chs 	unlk	%a6
    449  1.1  scottr 	rts
    450  1.1  scottr 
    451  1.1  scottr 
    452  1.1  scottr /*
    453  1.1  scottr  * iwmMotor -- switch drive motor on/off
    454  1.1  scottr  *
    455  1.1  scottr  * Parameters:	stack	l	drive ID (0/1)
    456  1.1  scottr  *		stack	l	on(1)/off(0)
    457  1.3     chs  * Returns:	%d0		motor cmd
    458  1.1  scottr  */
    459  1.1  scottr ENTRY(iwmMotor)
    460  1.3     chs 	link	%a6,#0
    461  1.3     chs 	moveml	%a0-%a1,%sp@-
    462  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    463  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    464  1.1  scottr 
    465  1.3     chs 	movel	%a6@(8),%d0		| Get drive #
    466  1.1  scottr 	bne	mtDrv1
    467  1.3     chs 	tstb	%a0@(intDrive)
    468  1.1  scottr 	bra	mtSwitch
    469  1.1  scottr mtDrv1:
    470  1.3     chs 	tstb	%a0@(extDrive)
    471  1.1  scottr mtSwitch:
    472  1.3     chs 	movel	#motorOnCmd,%d0		| Motor ON
    473  1.3     chs 	tstl	%a6@(12)
    474  1.1  scottr 	bne	mtON
    475  1.3     chs 	movel	#motorOffCmd,%d0
    476  1.1  scottr mtON:
    477  1.1  scottr 	bsr	driveCmd
    478  1.1  scottr 
    479  1.3     chs 	moveml	%sp@+,%a0-%a1
    480  1.3     chs 	unlk	%a6
    481  1.1  scottr 	rts
    482  1.1  scottr 
    483  1.1  scottr 
    484  1.1  scottr /*
    485  1.1  scottr  * iwmSelectSide -- select side 0 (lower head) / side 1 (upper head).
    486  1.1  scottr  *
    487  1.1  scottr  * This MUST be called immediately before an actual read/write access.
    488  1.1  scottr  *
    489  1.1  scottr  * Parameters:	stack	l	side bit (0/1)
    490  1.1  scottr  * Returns:	-
    491  1.1  scottr  */
    492  1.1  scottr ENTRY(iwmSelectSide)
    493  1.3     chs 	link	%a6,#0
    494  1.3     chs 	moveml	%d1/%a0-%a1,%sp@-
    495  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    496  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    497  1.1  scottr 
    498  1.3     chs 	moveq	#0x0B,%d0		| Drive ready for reading?
    499  1.1  scottr 	bsr	selDriveReg		| (undocumented)
    500  1.1  scottr ss01:
    501  1.1  scottr 	bsr	dstatus
    502  1.1  scottr 	bmi	ss01
    503  1.1  scottr 
    504  1.3     chs 	moveq	#rdDataFrom0,%d0	| Lower head
    505  1.3     chs 	movel	%a6@(0x08),%d1		| Get side #
    506  1.1  scottr 	beq	ssSide0
    507  1.3     chs 	moveq	#rdDataFrom1,%d0	| Upper head
    508  1.1  scottr ssSide0:
    509  1.1  scottr 	bsr	driveStat
    510  1.1  scottr 
    511  1.3     chs 	moveml	%sp@+,%d1/%a0-%a1
    512  1.3     chs 	unlk	%a6
    513  1.1  scottr 	rts
    514  1.1  scottr 
    515  1.1  scottr 
    516  1.1  scottr /*
    517  1.1  scottr  * iwmTrack00 -- move head to track 00 for drive calibration.
    518  1.1  scottr  *
    519  1.1  scottr  * XXX Drive makes funny noises during resore. Tune delay/retry count?
    520  1.1  scottr  *
    521  1.1  scottr  * Parameters:	-
    522  1.3     chs  * Returns:	%d0		result code
    523  1.1  scottr  */
    524  1.1  scottr ENTRY(iwmTrack00)
    525  1.3     chs 	link	%a6,#0
    526  1.3     chs 	moveml	%d1-%d4/%a0-%a1,%sp@-
    527  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    528  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    529  1.1  scottr 
    530  1.3     chs 	moveq	#motorOnCmd,%d0		| Switch drive motor on
    531  1.1  scottr 	bsr	driveCmd
    532  1.1  scottr 
    533  1.3     chs 	moveq	#stepOutCmd,%d0		| Step out
    534  1.1  scottr 	bsr	driveCmd
    535  1.1  scottr 
    536  1.3     chs 	movew	#100,%d2		| Max. tries
    537  1.1  scottr t0Retry:
    538  1.3     chs 	moveq	#atTrack00,%d0		| Already at track 0?
    539  1.1  scottr 	bsr	driveStat
    540  1.1  scottr 	bpl	isTrack00		| Track 0 => Bit 7 = 0
    541  1.1  scottr 
    542  1.3     chs 	moveq	#doStepCmd,%d0		| otherwise step
    543  1.1  scottr 	bsr	driveCmd
    544  1.3     chs 	movew	#80,%d4			| Retries
    545  1.1  scottr t0Still:
    546  1.3     chs 	moveq	#stillStepping,%d0	| Drive is still stepping?
    547  1.1  scottr 	bsr	driveStat
    548  1.3     chs 	dbmi	%d4,t0Still
    549  1.1  scottr 
    550  1.3     chs 	cmpiw	#-1,%d4
    551  1.1  scottr 	bne	t002
    552  1.1  scottr 
    553  1.3     chs 	moveq	#cantStepErr,%d0	| Not ready after many retries
    554  1.1  scottr 	bra	t0Done
    555  1.1  scottr t002:
    556  1.1  scottr 
    557  1.1  scottr #if USE_DELAY
    558  1.3     chs 	movel	#15000,%sp@-
    559  1.1  scottr 	jsr	_C_LABEL(delay)		| in mac68k/clock.c
    560  1.3     chs 	addqw	#4,%sp
    561  1.1  scottr #else
    562  1.3     chs 	movew	#15,%d0
    563  1.1  scottr 	bsr	iwmDelay
    564  1.1  scottr #endif
    565  1.1  scottr 
    566  1.3     chs 	dbra	%d2,t0Retry
    567  1.1  scottr 
    568  1.3     chs 	moveq	#tk0BadErr,%d0		| Can't find track 00!!
    569  1.1  scottr 	bra	t0Done
    570  1.1  scottr 
    571  1.1  scottr isTrack00:
    572  1.3     chs 	moveq	#0,%d0
    573  1.1  scottr t0Done:
    574  1.3     chs 	moveml	%sp@+,%d1-%d4/%a0-%a1
    575  1.3     chs 	unlk	%a6
    576  1.3     chs 	rts
    577  1.1  scottr 
    578  1.1  scottr 
    579  1.1  scottr /*
    580  1.1  scottr  * iwmSeek -- do specified # of steps (positive - in, negative - out).
    581  1.1  scottr  *
    582  1.1  scottr  * Parameters:	stack	l	# of steps
    583  1.3     chs  * returns:	%d0		result code
    584  1.1  scottr  */
    585  1.1  scottr ENTRY(iwmSeek)
    586  1.3     chs 	link	%a6,#0
    587  1.3     chs 	moveml	%d1-%d4/%a0-%a1,%sp@-
    588  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
    589  1.3     chs 	movel	_C_LABEL(Via1Base),%a1
    590  1.1  scottr 
    591  1.3     chs 	moveq	#motorOnCmd,%d0		| Switch drive motor on
    592  1.1  scottr 	bsr	driveCmd
    593  1.1  scottr 
    594  1.3     chs 	moveq	#stepInCmd,%d0		| Set step IN
    595  1.3     chs 	movel	%a6@(8),%d2		| Get # of steps from stack
    596  1.1  scottr 	beq	stDone			| 0 steps? Nothing to do.
    597  1.1  scottr 	bpl	stepOut
    598  1.1  scottr 
    599  1.3     chs 	moveq	#stepOutCmd,%d0		| Set step OUT
    600  1.3     chs 	negl	%d2			| Make # of steps positive
    601  1.1  scottr stepOut:
    602  1.3     chs 	subql	#1,%d2			| Loop exits for -1
    603  1.1  scottr 	bsr	driveCmd		| Set direction
    604  1.1  scottr stLoop:
    605  1.3     chs 	moveq	#doStepCmd,%d0
    606  1.1  scottr 	bsr	driveCmd		| Step one!
    607  1.3     chs 	movew	#80,%d4			| Retries
    608  1.1  scottr st01:
    609  1.3     chs 	moveq	#stillStepping, %d0	| Drive is still stepping?
    610  1.1  scottr 	bsr	driveStat
    611  1.3     chs 	dbmi	%d4,st01
    612  1.1  scottr 
    613  1.3     chs 	cmpiw	#-1,%d4
    614  1.1  scottr 	bne	st02
    615  1.1  scottr 
    616  1.3     chs 	moveq	#cantStepErr,%d2	| Not ready after many retries
    617  1.1  scottr 	bra	stDone
    618  1.1  scottr st02:
    619  1.1  scottr 
    620  1.1  scottr #if USE_DELAY
    621  1.3     chs 	movel	#30,%sp@-
    622  1.1  scottr 	jsr	_C_LABEL(delay)		| in mac68k/clock.c
    623  1.3     chs 	addqw	#4,%sp
    624  1.1  scottr #else
    625  1.3     chs 	movew	_C_LABEL(TimeDBRA),%d4	| dbra loops per ms
    626  1.3     chs 	lsrw	#5,%d4			| DIV 32
    627  1.3     chs st03:	dbra	%d4,st03		| makes ca. 30 us
    628  1.1  scottr #endif
    629  1.1  scottr 
    630  1.3     chs 	dbra	%d2,stLoop
    631  1.1  scottr 
    632  1.3     chs 	moveq	#0,%d2			| All is well
    633  1.1  scottr stDone:
    634  1.3     chs 	movel	%d2,%d0
    635  1.3     chs 	moveml	%sp@+,%d1-%d4/%a0-%a1
    636  1.3     chs 	unlk	%a6
    637  1.1  scottr 	rts
    638  1.1  scottr 
    639  1.1  scottr 
    640  1.1  scottr /*
    641  1.1  scottr  * iwmReadSector -- read and decode the next available sector.
    642  1.1  scottr  *
    643  1.1  scottr  * TODO:	Poll SCC as long as interrupts are disabled (see top comment)
    644  1.1  scottr  *		Add a branch for Verify (compare to buffer)
    645  1.1  scottr  *		Understand and document the checksum algorithm!
    646  1.1  scottr  *
    647  1.2  scottr  *		XXX make "sizeof cylCache_t" a symbolic constant
    648  1.2  scottr  *
    649  1.3     chs  * Parameters:	%fp+08	l	Address of sector data buffer (512 bytes)
    650  1.3     chs  *		%fp+12	l	Address of sector header struct (I/O)
    651  1.3     chs  *		%fp+16	l	Address of cache buffer ptr array
    652  1.3     chs  * Returns:	%d0		result code
    653  1.3     chs  * Local:	%fp-2	w	CPU status register
    654  1.3     chs  *		%fp-3	b	side,
    655  1.3     chs  *		%fp-4	b	track,
    656  1.3     chs  *		%fp-5	b	sector wanted
    657  1.3     chs  *		%fp-6	b	retry count
    658  1.3     chs  *		%fp-7	b	sector read
    659  1.1  scottr  */
    660  1.1  scottr ENTRY(iwmReadSector)
    661  1.3     chs 	link	%a6,#-8
    662  1.3     chs 	moveml	%d1-%d7/%a0-%a5,%sp@-
    663  1.1  scottr 
    664  1.3     chs  	movel	_C_LABEL(Via1Base),%a1
    665  1.3     chs 	movel	%a6@(o_hdr),%a4		| Addr of sector header struct
    666  1.1  scottr 
    667  1.3     chs 	moveb	%a4@+,%a6@(-3)		| Save side bit,
    668  1.3     chs 	moveb	%a4@+,%a6@(-4)		| track#,
    669  1.3     chs 	moveb	%a4@,%a6@(-5)		| sector#
    670  1.3     chs 	moveb	#2*maxGCRSectors,%a6@(-6) | Max. retry count
    671  1.1  scottr 
    672  1.3     chs 	movew	%sr,%a6@(-2)		| Save CPU status register
    673  1.3     chs 	oriw	#0x0600,%sr		| Block all interrupts
    674  1.1  scottr 
    675  1.2  scottr rsNextSect:
    676  1.3     chs 	movel	%a6@(o_hdr),%a4		| Addr of sector header struct
    677  1.1  scottr 	bsr	readSectHdr		| Get next available SECTOR header
    678  1.1  scottr 	bne	rsDone			| Return if error
    679  1.1  scottr 
    680  1.1  scottr 	/*
    681  1.1  scottr 	 * Is this the right track & side? If not, return with error
    682  1.1  scottr 	 */
    683  1.3     chs 	movel	%a6@(o_hdr),%a4		| Sector header struct
    684  1.1  scottr 
    685  1.3     chs 	moveb	%a4@(o_side),%d1	| Get actual side
    686  1.3     chs 	lsrb	#3,%d1			| "Normalize" side bit (to bit 0)
    687  1.3     chs 	andb	#1,%d1
    688  1.3     chs 	moveb	%a6@(-3),%d2		| Get wanted side
    689  1.3     chs 	eorb	%d1,%d2			| Compare side bits
    690  1.1  scottr 	bne	rsSeekErr		| Should be equal!
    691  1.1  scottr 
    692  1.3     chs 	moveb	%a6@(-4),%d1		| Get track# we want
    693  1.3     chs 	cmpb	%a4@(o_track),%d1	| Compare to the header we've read
    694  1.1  scottr 	beq	rsGetSect
    695  1.2  scottr 
    696  1.1  scottr rsSeekErr:
    697  1.3     chs 	moveq	#seekErr,%d0		| Wrong track or side found
    698  1.1  scottr 	bra	rsDone
    699  1.1  scottr 
    700  1.1  scottr 	/*
    701  1.1  scottr 	 * Check for sector data lead-in 'D5 AA AD'
    702  1.1  scottr 	 * Registers:
    703  1.3     chs 	 *	%a0 points to data register of IWM as set up by readSectHdr
    704  1.3     chs 	 *	%a2 points to 'diskTo' translation table
    705  1.3     chs 	 *	%a4 points to tags buffer
    706  1.1  scottr 	 */
    707  1.1  scottr rsGetSect:
    708  1.3     chs 	moveb	%a4@(2),%a6@(-7)	| save sector number
    709  1.3     chs 	lea	%a4@(3),%a4		| Beginning of tag buffer
    710  1.3     chs 	moveq	#50,%d3			| Max. retries for sector lookup
    711  1.1  scottr rsLeadIn:
    712  1.3     chs 	lea	dataLeadIn,%a3		| Sector data lead-in
    713  1.3     chs 	moveq	#0x03,%d4		| is 3 bytes long
    714  1.1  scottr rsLI1:
    715  1.3     chs 	moveb	%a0@,%d2		| Get next byte
    716  1.1  scottr 	bpl	rsLI1
    717  1.3     chs 	dbra	%d3,rsLI2
    718  1.3     chs 	moveq	#noDtaMkErr,%d0		| Can't find a data mark
    719  1.1  scottr 	bra	rsDone
    720  1.1  scottr 
    721  1.1  scottr rsLI2:
    722  1.3     chs 	cmpb	%a3@+,%d2
    723  1.1  scottr 	bne	rsLeadIn		| If ne restart scan
    724  1.3     chs 	subqw	#1,%d4
    725  1.1  scottr 	bne	rsLI1
    726  1.2  scottr 
    727  1.1  scottr 	/*
    728  1.1  scottr 	 * We have found the lead-in. Now get the 12 tag bytes.
    729  1.3     chs 	 * (We leave %a3 pointing to 'dataLeadOut' for later.)
    730  1.1  scottr 	 */
    731  1.1  scottr rsTagNyb0:
    732  1.3     chs 	moveb	%a0@,%d3		| Get a char,
    733  1.1  scottr 	bpl	rsTagNyb0
    734  1.3     chs 	moveb	%a2@(0,%d3),%a4@+	| remap and store it
    735  1.1  scottr 
    736  1.3     chs 	moveq	#0,%d5			| Clear checksum registers
    737  1.3     chs 	moveq	#0,%d6
    738  1.3     chs 	moveq	#0,%d7
    739  1.3     chs 	moveq	#10,%d4			| Loop counter
    740  1.3     chs 	moveq	#0,%d3			| Data scratch reg
    741  1.1  scottr 
    742  1.1  scottr rsTags:
    743  1.1  scottr rsTagNyb1:
    744  1.3     chs 	moveb	%a0@,%d3		| Get 2 bit nibbles
    745  1.1  scottr 	bpl	rsTagNyb1
    746  1.3     chs 	moveb	%a2@(0,%d3),%d1		| Remap disk byte
    747  1.3     chs 	rolb	#2,%d1
    748  1.3     chs 	moveb	%d1,%d2
    749  1.3     chs 	andib	#0xC0,%d2		| Get top 2 bits for first byte
    750  1.1  scottr rsTagNyb2:
    751  1.3     chs 	moveb	%a0@,%d3		| Get first 6 bit nibble
    752  1.1  scottr 	bpl	rsTagNyb2
    753  1.3     chs 	orb	%a2@(0,%d3),%d2		| Remap it and complete first byte
    754  1.1  scottr 
    755  1.3     chs 	moveb	%d7,%d3			| The X flag bit (a copy of the carry
    756  1.3     chs 	addb	%d7,%d3			| flag) is added with the next addx
    757  1.1  scottr 
    758  1.3     chs 	rolb	#1,%d7
    759  1.3     chs 	eorb	%d7,%d2
    760  1.3     chs 	moveb	%d2,%a4@+		| Store tag byte
    761  1.3     chs 	addxb	%d2,%d5			| See above
    762  1.3     chs 
    763  1.3     chs 	rolb	#2,%d1
    764  1.3     chs 	moveb	%d1,%d2
    765  1.3     chs 	andib	#0xC0,%d2		| Get top 2 bits for second byte
    766  1.1  scottr rsTagNyb3:
    767  1.3     chs 	moveb	%a0@,%d3		| Get second 6 bit nibble
    768  1.1  scottr 	bpl	rsTagNyb3
    769  1.3     chs 	orb	%a2@(0,%d3),%d2		| remap it and complete byte
    770  1.3     chs 	eorb	%d5,%d2
    771  1.3     chs 	moveb	%d2,%a4@+		| Store tag byte
    772  1.3     chs 	addxb	%d2,%d6
    773  1.1  scottr 
    774  1.3     chs 	rolb	#2,%d1
    775  1.3     chs 	andib	#0xC0,%d1		| Get top 2 bits for third byte
    776  1.1  scottr rsTagNyb4:
    777  1.3     chs 	moveb	%a0@,%d3		| Get third 6 bit nibble
    778  1.1  scottr 	bpl	rsTagNyb4
    779  1.3     chs 	orb	%a2@(0,%d3),%d1		| remap it and complete byte
    780  1.3     chs 	eorb	%d6,%d1
    781  1.3     chs 	moveb	%d1,%a4@+		| Store tag byte
    782  1.3     chs 	addxb	%d1,%d7
    783  1.1  scottr 
    784  1.3     chs 	subqw	#3,%d4			| Update byte counter (four 6&2 encoded
    785  1.1  scottr 	bpl	rsTags			| disk bytes make three data bytes).
    786  1.2  scottr 
    787  1.1  scottr 	/*
    788  1.1  scottr 	 * Jetzt sind wir hier...
    789  1.1  scottr 	 * ...und Thomas D. hat noch was zu sagen...
    790  1.1  scottr 	 *
    791  1.1  scottr 	 * We begin to read in the actual sector data.
    792  1.2  scottr 	 * Compare sector # to what we wanted: If it matches, read directly
    793  1.2  scottr 	 * to buffer, else read to track cache.
    794  1.1  scottr 	 */
    795  1.3     chs 	movew	#0x01FE,%d4		| Loop counter
    796  1.3     chs 	moveq	#0,%d1			| Clear %d1
    797  1.3     chs 	moveb	%a6@(-7),%d1		| Get sector# we have read
    798  1.3     chs 	cmpb	%a6@(-5),%d1		| Compare to the sector# we want
    799  1.2  scottr 	bne	rsToCache
    800  1.3     chs 	movel	%a6@(o_buf),%a4		| Sector data buffer
    801  1.2  scottr 	bra	rsData
    802  1.2  scottr rsToCache:
    803  1.3     chs 	movel	%a6@(o_rslots),%a4	| Base address of slot array
    804  1.3     chs 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
    805  1.3     chs 	movel	#-1,%a4@(o_valid,%d1)
    806  1.3     chs 	movel	%a4@(o_secbuf,%d1),%a4	| and get its buffer ptr
    807  1.1  scottr rsData:
    808  1.1  scottr rsDatNyb1:
    809  1.3     chs 	moveb	%a0@,%d3		| Get 2 bit nibbles
    810  1.1  scottr 	bpl	rsDatNyb1
    811  1.3     chs 	moveb	%a2@(0,%d3),%d1		| Remap disk byte
    812  1.3     chs 	rolb	#2,%d1
    813  1.3     chs 	moveb	%d1,%d2
    814  1.3     chs 	andib	#0xC0,%d2		| Get top 2 bits for first byte
    815  1.1  scottr rsDatNyb2:
    816  1.3     chs 	moveb	%a0@,%d3		| Get first 6 bit nibble
    817  1.1  scottr 	bpl	rsDatNyb2
    818  1.3     chs 	orb	%a2@(0,%d3),%d2		| Remap it and complete first byte
    819  1.1  scottr 
    820  1.3     chs 	moveb	%d7,%d3			| The X flag bit (a copy of the carry
    821  1.3     chs 	addb	%d7,%d3			| flag) is added with the next addx
    822  1.1  scottr 
    823  1.3     chs 	rolb	#1,%d7
    824  1.3     chs 	eorb	%d7,%d2
    825  1.3     chs 	moveb	%d2,%a4@+		| Store data byte
    826  1.3     chs 	addxb	%d2,%d5			| See above
    827  1.3     chs 
    828  1.3     chs 	rolb	#2,%d1
    829  1.3     chs 	moveb	%d1,%d2
    830  1.3     chs 	andib	#0xC0,%d2		| Get top 2 bits for second byte
    831  1.1  scottr rsDatNyb3:
    832  1.3     chs 	moveb	%a0@,%d3		| Get second 6 bit nibble
    833  1.1  scottr 	bpl	rsDatNyb3
    834  1.3     chs 	orb	%a2@(0,%d3),%d2		| Remap it and complete byte
    835  1.3     chs 	eorb	%d5,%d2
    836  1.3     chs 	moveb	%d2,%a4@+		| Store data byte
    837  1.3     chs 	addxb	%d2,%d6
    838  1.3     chs 	tstw	%d4
    839  1.1  scottr 	beq	rsCkSum			| Data read, continue with checksums
    840  1.1  scottr 
    841  1.3     chs 	rolb	#2,%d1
    842  1.3     chs 	andib	#0xC0,%d1		| Get top 2 bits for third byte
    843  1.1  scottr rsDatNyb4:
    844  1.3     chs 	moveb	%a0@,%d3		| Get third 6 bit nibble
    845  1.1  scottr 	bpl	rsDatNyb4
    846  1.3     chs 	orb	%a2@(0,%d3),%d1		| Remap it and complete byte
    847  1.3     chs 	eorb	%d6,%d1
    848  1.3     chs 	moveb	%d1,%a4@+		| Store data byte
    849  1.3     chs 	addxb	%d1,%d7
    850  1.3     chs 	subqw	#3,%d4			| Update byte counter
    851  1.1  scottr 	bra	rsData
    852  1.1  scottr 
    853  1.1  scottr 	/*
    854  1.1  scottr 	 * Next read checksum bytes
    855  1.1  scottr 	 * While reading the sector data, three separate checksums are
    856  1.3     chs 	 * maintained in %D5/%D6/%D7 for the 1st/2nd/3rd data byte of
    857  1.3     chs 	 * each group.
    858  1.1  scottr 	 */
    859  1.1  scottr rsCkSum:
    860  1.1  scottr rsCkS1:
    861  1.3     chs 	moveb	%a0@,%d3		| Get 2 bit nibbles
    862  1.1  scottr 	bpl	rsCkS1
    863  1.3     chs 	moveb	%a2@(0,%d3),%d1		| Remap disk byte
    864  1.1  scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    865  1.3     chs 	rolb	#2,%d1
    866  1.3     chs 	moveb	%d1,%d2
    867  1.3     chs 	andib	#0xC0,%d2		| Get top 2 bits for first byte
    868  1.1  scottr rsCkS2:
    869  1.3     chs 	moveb	%a0@,%d3		| Get first 6 bit nibble
    870  1.1  scottr 	bpl	rsCkS2
    871  1.3     chs 	moveb	%a2@(0,%d3),%d3		| and remap it
    872  1.1  scottr 	bmi	rsBadCkSum		| Fault! ( > 0x3f is bad read)
    873  1.3     chs 	orb	%d3,%d2			| Merge 6&2
    874  1.3     chs 	cmpb	%d2,%d5			| Compare first checksum to %D5
    875  1.1  scottr 	bne	rsBadCkSum		| Fault! (Checksum)
    876  1.1  scottr 
    877  1.3     chs 	rolb	#2,%d1
    878  1.3     chs 	moveb	%d1,%d2
    879  1.3     chs 	andib	#0xC0,%d2		| Get top 2 bits for second byte
    880  1.1  scottr rsCkS3:
    881  1.3     chs 	moveb	%a0@,%d3		| Get second 6 bit nibble
    882  1.1  scottr 	bpl	rsCkS3
    883  1.3     chs 	moveb	%a2@(0,%d3),%d3		| and remap it
    884  1.1  scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    885  1.3     chs 	orb	%d3,%d2			| Merge 6&2
    886  1.3     chs 	cmpb	%d2,%d6			| Compare second checksum to %D6
    887  1.1  scottr 	bne	rsBadCkSum		| Fault! (Checksum)
    888  1.1  scottr 
    889  1.3     chs 	rolb	#2,%d1
    890  1.3     chs 	andib	#0xC0,%d1		| Get top 2 bits for second byte
    891  1.1  scottr rsCkS4:
    892  1.3     chs 	moveb	%a0@,%d3		| Get third 6 bit nibble
    893  1.1  scottr 	bpl	rsCkS4
    894  1.3     chs 	moveb	%a2@(0,%d3),%d3		| and remap it
    895  1.1  scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    896  1.3     chs 	orb	%d3,%d1			| Merge 6&2
    897  1.3     chs 	cmpb	%d1,%d7			| Compare third checksum to %D7
    898  1.1  scottr 	beq	rsLdOut			| Fault! (Checksum)
    899  1.1  scottr 
    900  1.1  scottr rsBadCkSum:
    901  1.3     chs 	moveq	#badDCkSum,%d0		| Bad data mark checksum
    902  1.1  scottr 	bra	rsDone
    903  1.1  scottr 
    904  1.1  scottr rsBadDBtSlp:
    905  1.3     chs 	moveq	#badDBtSlp,%d0		| One of the data mark bit slip
    906  1.1  scottr 	bra	rsDone			| nibbles was incorrect
    907  1.1  scottr 
    908  1.1  scottr 	/*
    909  1.1  scottr 	 * We have gotten the checksums allright, now look for the
    910  1.1  scottr 	 * sector data lead-out 'DE AA'
    911  1.3     chs 	 * (We have %a3 still pointing to 'dataLeadOut'; this part of the
    912  1.1  scottr 	 * table is used for writing to disk, too.)
    913  1.1  scottr 	 */
    914  1.1  scottr rsLdOut:
    915  1.3     chs 	moveq	#1,%d4			| Is two bytes long {1,0}
    916  1.1  scottr rsLdOut1:
    917  1.3     chs 	moveb	%a0@,%d3		| Get token
    918  1.1  scottr 	bpl	rsLdOut1
    919  1.3     chs 	cmpb	%a3@+,%d3
    920  1.1  scottr 	bne	rsBadDBtSlp		| Fault!
    921  1.3     chs 	dbra	%d4,rsLdOut1
    922  1.3     chs 	moveq	#0,%d0			| OK.
    923  1.2  scottr 
    924  1.2  scottr 	/*
    925  1.2  scottr 	 * See if we got the sector we wanted. If not, and no error
    926  1.2  scottr 	 * occurred, mark buffer valid. Else ignore the sector.
    927  1.2  scottr 	 * Then, read on.
    928  1.2  scottr 	 */
    929  1.1  scottr rsDone:
    930  1.3     chs 	movel	%a6@(o_hdr),%a4		| Addr of sector header struct
    931  1.3     chs 	moveb	%a4@(o_sector),%d1	| Get # of sector we have just read
    932  1.3     chs 	cmpb	%a6@(-5),%d1		| Compare to the sector we want
    933  1.2  scottr 	beq	rsAllDone
    934  1.2  scottr 
    935  1.3     chs 	tstb	%d0			| Any error? Simply ignore data
    936  1.2  scottr 	beq	rsBufValid
    937  1.3     chs 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
    938  1.3     chs 	movel	%a6@(o_rslots),%a4
    939  1.3     chs 	clrl	%a4@(o_valid,%d1)	| Mark buffer content "invalid"
    940  1.2  scottr 
    941  1.2  scottr rsBufValid:
    942  1.3     chs 	subqb	#1,%a6@(-6)		| max. retries
    943  1.2  scottr 	bne	rsNextSect
    944  1.2  scottr 					| Sector not found, but
    945  1.3     chs 	tstb	%d0			| don't set error code if we
    946  1.2  scottr 	bne	rsAllDone		| already have one.
    947  1.3     chs 	moveq	#sectNFErr,%d0
    948  1.2  scottr rsAllDone:
    949  1.3     chs 	movew	%a6@(-2),%sr		| Restore interrupt mask
    950  1.3     chs 	moveml	%sp@+,%d1-%d7/%a0-%a5
    951  1.3     chs 	unlk	%a6
    952  1.2  scottr 	rts
    953  1.1  scottr 
    954  1.1  scottr 
    955  1.1  scottr /*
    956  1.1  scottr  * iwmWriteSector -- encode and write data to the specified sector.
    957  1.1  scottr  *
    958  1.1  scottr  * TODO:	Poll SCC as long as interrupts are disabled (see top comment)
    959  1.1  scottr  *		Understand and document the checksum algorithm!
    960  1.1  scottr  *
    961  1.2  scottr  *		XXX Use registers more efficiently
    962  1.2  scottr  *
    963  1.3     chs  * Parameters:	%fp+8	l	Address of sector header struct (I/O)
    964  1.3     chs  *		%fp+12	l	Address of cache buffer ptr array
    965  1.3     chs  * Returns:	%d0		result code
    966  1.3     chs  *
    967  1.3     chs  * Local:	%fp-2	w	CPU status register
    968  1.3     chs  *		%fp-3	b	side,
    969  1.3     chs  *		%fp-4	b	track,
    970  1.3     chs  *		%fp-5	b	sector wanted
    971  1.3     chs  *		%fp-6	b	retry count
    972  1.3     chs  *		%fp-10	b	current slot
    973  1.1  scottr  */
    974  1.1  scottr ENTRY(iwmWriteSector)
    975  1.3     chs 	link	%a6,#-10
    976  1.3     chs 	moveml	%d1-%d7/%a0-%a5,%sp@-
    977  1.1  scottr 
    978  1.3     chs  	movel	_C_LABEL(Via1Base),%a1
    979  1.3     chs 	movel	%a6@(o_hdr),%a4		| Addr of sector header struct
    980  1.1  scottr 
    981  1.3     chs 	moveb	%a4@+,%a6@(-3)		| Save side bit,
    982  1.3     chs 	moveb	%a4@+,%a6@(-4)		| track#,
    983  1.3     chs 	moveb	%a4@,%a6@(-5)		| sector#
    984  1.3     chs 	moveb	#maxGCRSectors,%a6@(-6)	| Max. retry count
    985  1.1  scottr 
    986  1.3     chs 	movew	%sr,%a6@(-2)		| Save CPU status register
    987  1.3     chs 	oriw	#0x0600,%sr		| Block all interrupts
    988  1.1  scottr 
    989  1.2  scottr wsNextSect:
    990  1.3     chs 	movel	%a6@(o_hdr),%a4
    991  1.1  scottr 	bsr	readSectHdr		| Get next available sector header
    992  1.2  scottr 	bne	wsAllDone		| Return if error
    993  1.1  scottr 
    994  1.1  scottr 	/*
    995  1.1  scottr 	 * Is this the right track & side? If not, return with error
    996  1.1  scottr 	 */
    997  1.3     chs 	movel	%a6@(o_hdr),%a4		| Sector header struct
    998  1.1  scottr 
    999  1.3     chs 	moveb	%a4@(o_side),%d1	| Get side#
   1000  1.3     chs 	lsrb	#3,%d1			| "Normalize" side bit...
   1001  1.3     chs 	andb	#1,%d1
   1002  1.3     chs 	moveb	%a6@(-3),%d2		| Get wanted side
   1003  1.3     chs 	eorb	%d1,%d2			| Compare side bits
   1004  1.1  scottr 	bne	wsSeekErr
   1005  1.1  scottr 
   1006  1.3     chs 	moveb	%a6@(-4),%d1		| Get wanted track#
   1007  1.3     chs 	cmpb	%a4@(o_track),%d1	| Compare to the read header
   1008  1.1  scottr 	beq	wsCompSect
   1009  1.1  scottr 
   1010  1.1  scottr wsSeekErr:
   1011  1.3     chs 	moveq	#seekErr,%d0		| Wrong track or side
   1012  1.2  scottr 	bra	wsAllDone
   1013  1.1  scottr 
   1014  1.1  scottr 	/*
   1015  1.2  scottr 	 * Look up the current sector number in the cache.
   1016  1.2  scottr 	 * If the buffer is dirty ("valid"), write it to disk. If not,
   1017  1.2  scottr 	 * loop over all the slots and return if all of them are clean.
   1018  1.2  scottr 	 *
   1019  1.2  scottr 	 * Alternatively, we could decrement a "dirty sectors" counter here.
   1020  1.1  scottr 	 */
   1021  1.1  scottr wsCompSect:
   1022  1.3     chs 	moveq	#0,%d1			| Clear register
   1023  1.3     chs 	moveb	%a4@(o_sector),%d1	| get the # of header read
   1024  1.3     chs 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
   1025  1.3     chs 	movel	%a6@(o_wslots),%a4
   1026  1.3     chs 	tstl	%a4@(o_valid,%d1)	| Sector dirty?
   1027  1.2  scottr 	bne	wsBufDirty
   1028  1.2  scottr 
   1029  1.3     chs 	moveq	#maxGCRSectors-1,%d2	| Any dirty sectors left?
   1030  1.2  scottr wsChkDty:
   1031  1.3     chs 	movew	%d2,%d1
   1032  1.3     chs 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
   1033  1.3     chs 	tstl	%a4@(o_valid,%d1)
   1034  1.2  scottr 	bne	wsNextSect		| Sector dirty?
   1035  1.3     chs 	dbra	%d2,wsChkDty
   1036  1.2  scottr 
   1037  1.2  scottr 	bra	wsAllDone		| We are through with this track.
   1038  1.2  scottr 
   1039  1.1  scottr 
   1040  1.1  scottr 	/*
   1041  1.1  scottr 	 * Write sync pattern and sector data lead-in 'D5 AA'. The
   1042  1.1  scottr 	 * missing 'AD' is made up by piping 0x0B through the nibble
   1043  1.1  scottr 	 * table (toDisk).
   1044  1.1  scottr 	 *
   1045  1.1  scottr 	 * To set up IWM for writing:
   1046  1.1  scottr 	 *
   1047  1.1  scottr 	 * access q6H & write first byte to q7H.
   1048  1.1  scottr 	 * Then check bit 7 of q6L (status reg) for 'IWM ready'
   1049  1.1  scottr 	 * and write subsequent bytes to q6H.
   1050  1.1  scottr 	 *
   1051  1.1  scottr 	 * Registers:
   1052  1.3     chs 	 *	%a0	IWM base address (later: data register)
   1053  1.3     chs 	 *	%a1	Via1Base
   1054  1.3     chs 	 *	%a2	IWM handshake register
   1055  1.3     chs 	 *	%a3	data (tags buffer, data buffer)
   1056  1.3     chs 	 *	%a4	Sync pattern, 'toDisk' translation table
   1057  1.1  scottr 	 */
   1058  1.2  scottr wsBufDirty:
   1059  1.3     chs 	movel	_C_LABEL(IWMBase),%a0
   1060  1.3     chs 	lea	%a4@(0,%d1),%a3
   1061  1.3     chs 	movel	%a3,%a6@(-10)		| Save ptr to current slot
   1062  1.3     chs 	tstb	%a0@(q6H)		| Enable writing to disk
   1063  1.3     chs 	movel	%a6@(o_hdr),%a4		| Sector header struct
   1064  1.3     chs 	lea	%a4@(o_Tags),%a3	| Point %a3 to tags buffer
   1065  1.3     chs 	lea	syncPattern,%a4
   1066  1.3     chs 
   1067  1.3     chs 	moveb	%a4@+,%a0@(q7H)		| Write first sync byte
   1068  1.3     chs 	lea	%a0@(q6L),%a2		| Point %a2 to handshake register
   1069  1.3     chs 	lea	%a0@(q6H),%a0		| Point %a0 to IWM data register
   1070  1.3     chs 
   1071  1.3     chs 	moveq	#6,%d0			| Loop counter for sync bytes
   1072  1.3     chs 	moveq	#0,%d2
   1073  1.3     chs 	moveq	#0,%d3
   1074  1.3     chs 	movel	#0x02010009,%d4		| Loop counters for tag/sector data
   1075  1.1  scottr 
   1076  1.1  scottr 	/*
   1077  1.1  scottr 	 * Write 5 sync bytes and first byte of sector data lead-in
   1078  1.1  scottr 	 */
   1079  1.1  scottr wsLeadIn:
   1080  1.3     chs 	moveb	%a4@+,%d1		| Get next sync byte
   1081  1.1  scottr wsLI1:
   1082  1.3     chs 	tstb	%a2@			| IWM ready?
   1083  1.1  scottr 	bpl	wsLI1
   1084  1.3     chs 	moveb	%d1,%a0@		| Write it to disk
   1085  1.3     chs 	subqw	#1,%d0
   1086  1.1  scottr 	bne	wsLeadIn
   1087  1.1  scottr 
   1088  1.3     chs 	moveb	%a4@+,%d1		| Write 2nd byte of sector lead-in
   1089  1.3     chs 	lea	toDisk,%a4		| Point %a4 to nibble translation table
   1090  1.1  scottr wsLI2:
   1091  1.3     chs 	tstb	%a2@			| IWM ready?
   1092  1.1  scottr 	bpl	wsLI2
   1093  1.3     chs 	moveb	%d1,%a0@		| Write it to disk
   1094  1.1  scottr 
   1095  1.3     chs 	moveq	#0,%d5			| Clear checksum registers
   1096  1.3     chs 	moveq	#0,%d6
   1097  1.3     chs 	moveq	#0,%d7
   1098  1.1  scottr 
   1099  1.3     chs 	moveq	#0x0B,%d1		| 3rd byte of sector data lead-in
   1100  1.1  scottr 					| (Gets translated to 0xAD)
   1101  1.3     chs 	moveb	%a3@+,%d2		| Get 1st byte from tags buffer
   1102  1.1  scottr 	bra	wsDataEntry
   1103  1.1  scottr 
   1104  1.1  scottr 	/*
   1105  1.1  scottr 	 * The following loop reads the content of the tags buffer (12 bytes)
   1106  1.1  scottr 	 * and the data buffer (512 bytes).
   1107  1.1  scottr 	 * Each pass reads out three bytes and
   1108  1.1  scottr 	 * a) splits them 6&2 into three 6 bit nibbles and a fourth byte
   1109  1.1  scottr 	 *    consisting of the three 2 bit nibbles
   1110  1.1  scottr 	 * b) encodes the nibbles with a table to disk bytes (bit 7 set, no
   1111  1.1  scottr 	 *    more than two consecutive zero bits) and writes them to disk as
   1112  1.1  scottr 	 *
   1113  1.1  scottr 	 *    00mmnnoo		fragment 2 bit nibbles
   1114  1.1  scottr 	 *    00mmmmmm		6 bit nibble -- first byte
   1115  1.1  scottr 	 *    00nnnnnn		6 bit nibble -- second byte
   1116  1.1  scottr 	 *    00oooooo		6 bit nibble -- third byte
   1117  1.1  scottr 	 *
   1118  1.1  scottr 	 * c) adds up three 8 bit checksums, one for each of the bytes written.
   1119  1.1  scottr 	 */
   1120  1.2  scottr wsSD1:
   1121  1.3     chs 	movel	%a6@(-10),%a3		| Get ptr to current slot
   1122  1.3     chs 	movel	%a3@(o_secbuf),%a3	| Get start of sector data buffer
   1123  1.1  scottr 
   1124  1.1  scottr wsData:
   1125  1.3     chs 	addxb	%d2,%d7
   1126  1.3     chs 	eorb	%d6,%d2
   1127  1.3     chs 	moveb	%d2,%d3
   1128  1.3     chs 	lsrw	#6,%d3			| Put 2 bit nibbles into place
   1129  1.1  scottr wsRDY01:
   1130  1.3     chs 	tstb	%a2@			| IWM ready?
   1131  1.1  scottr 	bpl	wsRDY01
   1132  1.3     chs 	moveb	%a4@(0,%d3),%a0@	| Translate nibble and write
   1133  1.3     chs 	subqw	#3,%d4			| Update counter
   1134  1.3     chs 	moveb	%d7,%d3
   1135  1.3     chs 	addb	%d7,%d3			| Set X flag (??)
   1136  1.3     chs 	rolb	#1,%d7
   1137  1.3     chs 	andib	#0x3F,%d0
   1138  1.1  scottr wsRDY02:
   1139  1.3     chs 	tstb	%a2@			| IWM ready?
   1140  1.1  scottr 	bpl	wsRDY02
   1141  1.3     chs 	moveb	%a4@(0,%d0),%a0@	| Translate nibble and write
   1142  1.1  scottr 
   1143  1.1  scottr 	/*
   1144  1.1  scottr 	 * We enter with the last byte of the sector data lead-in
   1145  1.3     chs 	 * between our teeth (%D1, that is).
   1146  1.1  scottr 	 */
   1147  1.1  scottr wsDataEntry:
   1148  1.3     chs 	moveb	%a3@+,%d0		| Get first byte
   1149  1.3     chs 	addxb	%d0,%d5
   1150  1.3     chs 	eorb	%d7,%d0
   1151  1.3     chs 	moveb	%d0,%d3			| Keep top two bits
   1152  1.3     chs 	rolw	#2,%d3			| by shifting them to MSByte
   1153  1.3     chs 	andib	#0x3F,%d1
   1154  1.1  scottr wsRDY03:
   1155  1.3     chs 	tstb	%a2@			| IWM ready?
   1156  1.1  scottr 	bpl	wsRDY03
   1157  1.3     chs 	moveb	%a4@(0,%d1),%a0@	| Translate nibble and write
   1158  1.1  scottr 
   1159  1.3     chs 	moveb	%a3@+,%d1			| Get second byte
   1160  1.3     chs 	addxb	%d1,%d6
   1161  1.3     chs 	eorb	%d5,%d1
   1162  1.3     chs 	moveb	%d1,%d3			| Keep top two bits
   1163  1.3     chs 	rolw	#2,%d3			| by shifting them to MSByte
   1164  1.3     chs 	andib	#0x3F,%d2
   1165  1.1  scottr wsRDY04:
   1166  1.3     chs 	tstb	%a2@			| IWM ready?
   1167  1.1  scottr 	bpl	wsRDY04
   1168  1.3     chs 	moveb	%a4@(0,%d2),%a0@	| Translate nibble and write
   1169  1.2  scottr 
   1170  1.1  scottr 	/*
   1171  1.1  scottr 	 * XXX We have a classic off-by-one error here: the last access
   1172  1.1  scottr 	 * reaches beyond the data buffer which bombs with memory
   1173  1.1  scottr 	 * protection. The value read isn't used anyway...
   1174  1.1  scottr 	 * Hopefully there is enough time for an additional check
   1175  1.1  scottr 	 * (exit the last loop cycle before the buffer access).
   1176  1.1  scottr 	 */
   1177  1.3     chs 	tstl	%d4			| Last loop cycle?
   1178  1.1  scottr 	beq	wsSDDone		| Then get out while we can.
   1179  1.1  scottr 
   1180  1.3     chs 	moveb	%a3@+,%d2		| Get third byte
   1181  1.3     chs 	tstw	%d4			| First write tag buffer,...
   1182  1.1  scottr 	bne	wsData
   1183  1.1  scottr 
   1184  1.3     chs 	swap	%d4			| ...then write data buffer
   1185  1.1  scottr 	bne	wsSD1
   1186  1.1  scottr 
   1187  1.1  scottr 	/*
   1188  1.1  scottr 	 * Write nibbles for last 2 bytes, then
   1189  1.1  scottr 	 * split checksum bytes in 6&2 and write them to disk
   1190  1.1  scottr 	 */
   1191  1.1  scottr wsSDDone:
   1192  1.3     chs 	clrb	%d3			| No 513th byte
   1193  1.3     chs 	lsrw	#6,%d3			| Set up 2 bit nibbles
   1194  1.1  scottr wsRDY05:
   1195  1.3     chs 	tstb	%a2@			| IWM ready?
   1196  1.1  scottr 	bpl	wsRDY05
   1197  1.3     chs 	moveb	%a4@(0,%d3),%a0@	| Write fragments
   1198  1.3     chs 	moveb	%d5,%d3
   1199  1.3     chs 	rolw	#2,%d3
   1200  1.3     chs 	moveb	%d6,%d3
   1201  1.3     chs 	rolw	#2,%d3
   1202  1.3     chs 	andib	#0x3F,%d0
   1203  1.1  scottr wsRDY06:
   1204  1.3     chs 	tstb	%a2@			| IWM ready?
   1205  1.1  scottr 	bpl	wsRDY06
   1206  1.3     chs 	moveb	%a4@(0,%d0),%a0@	| Write 511th byte
   1207  1.3     chs 	andib	#0x3F,%d1
   1208  1.1  scottr wsRDY07:
   1209  1.3     chs 	tstb	%a2@			| IWM ready?
   1210  1.1  scottr 	bpl	wsRDY07
   1211  1.3     chs 	moveb	%a4@(0,%d1),%a0@	| write 512th byte
   1212  1.3     chs 	moveb	%d7,%d3
   1213  1.3     chs 	lsrw	#6,%d3			| Get fragments ready
   1214  1.1  scottr wsRDY08:
   1215  1.3     chs 	tstb	%a2@			| IWM ready?
   1216  1.1  scottr 	bpl	wsRDY08
   1217  1.3     chs 	moveb	%a4@(0,%d3),%a0@	| Write fragments
   1218  1.3     chs 	andib	#0x3F,%d5
   1219  1.1  scottr wsRDY09:
   1220  1.3     chs 	tstb	%a2@			| IWM ready?
   1221  1.1  scottr 	bpl	wsRDY09
   1222  1.3     chs 	moveb	%a4@(0,%d5),%a0@	| Write first checksum byte
   1223  1.3     chs 	andib	#0x3F,%D6
   1224  1.1  scottr wsRDY10:
   1225  1.3     chs 	tstb	%a2@			| IWM ready?
   1226  1.1  scottr 	bpl	wsRDY10
   1227  1.3     chs 	moveb	%a4@(0,%d6),%a0@	| Write second checksum byte
   1228  1.3     chs 	andib	#0x3F,%d7
   1229  1.1  scottr wsRDY11:
   1230  1.3     chs 	tstb	%a2@			| IWM ready?
   1231  1.1  scottr 	bpl	wsRDY11
   1232  1.3     chs 	moveb	%a4@(0,%d7),%a0@	| Write third checksum byte
   1233  1.1  scottr 
   1234  1.1  scottr 	/*
   1235  1.1  scottr 	 * Write sector data lead-out
   1236  1.1  scottr 	 */
   1237  1.3     chs 	lea	dataLeadOut,%a4		| Sector data lead-out
   1238  1.3     chs 	moveq	#3,%d2			| Four bytes long {3,2,1,0}
   1239  1.1  scottr wsLeadOut:
   1240  1.3     chs 	moveb	%a2@,%d1		| IWM ready?
   1241  1.1  scottr 	bpl	wsLeadOut
   1242  1.3     chs 	moveb	%a4@+,%a0@		| Write lead-out
   1243  1.3     chs 	dbf	%d2,wsLeadOut
   1244  1.1  scottr 
   1245  1.3     chs 	moveq	#0,%d0
   1246  1.3     chs 	btst	#6,%d1			| Check IWM underrun bit
   1247  1.1  scottr 	bne	wsNoErr
   1248  1.1  scottr 
   1249  1.3     chs 	moveq	#wrUnderRun,%d0		| Could not write
   1250  1.1  scottr 					| fast enough to keep up with IWM
   1251  1.1  scottr wsNoErr:
   1252  1.3     chs 	tstb	%a0@(0x0200)		| q7L -- Write OFF
   1253  1.1  scottr 
   1254  1.1  scottr wsDone:
   1255  1.3     chs 	tstb	%d0			| Any error? Simply retry
   1256  1.2  scottr 	bne	wsBufInvalid
   1257  1.2  scottr 
   1258  1.3     chs 	movel	%a6@(-10),%a4		| Else, get ptr to current slot
   1259  1.3     chs 	clrl	%a4@(o_valid)		| Mark current buffer "clean"
   1260  1.2  scottr 	bra	wsNextSect
   1261  1.2  scottr 
   1262  1.2  scottr wsBufInvalid:
   1263  1.3     chs 	subqb	#1,%a6@(-6)		| retries
   1264  1.2  scottr 	bne	wsNextSect
   1265  1.2  scottr 					| Sector not found, but
   1266  1.3     chs 	tstb	%d0			| don't set error code if we
   1267  1.2  scottr 	bne	wsAllDone		| already have one.
   1268  1.3     chs 	moveq	#sectNFErr,%d0
   1269  1.2  scottr 
   1270  1.2  scottr wsAllDone:
   1271  1.3     chs 	movew	%a6@(-2),%sr		| Restore interrupt mask
   1272  1.3     chs 	moveml	%sp@+,%d1-%d7/%a0-%a5
   1273  1.3     chs 	unlk	%a6
   1274  1.1  scottr 	rts
   1275  1.1  scottr 
   1276  1.1  scottr 
   1277  1.1  scottr 
   1278  1.1  scottr /**
   1279  1.1  scottr  **	Local functions
   1280  1.1  scottr  **/
   1281  1.1  scottr 
   1282  1.1  scottr /*
   1283  1.1  scottr  * iwmDelay
   1284  1.1  scottr  *
   1285  1.1  scottr  * In-kernel calls to delay() in mac68k/clock.c bomb
   1286  1.1  scottr  *
   1287  1.3     chs  * Parameters:	%d0	delay in milliseconds
   1288  1.3     chs  * Trashes:	%d0, %d1
   1289  1.1  scottr  * Returns:	-
   1290  1.1  scottr  */
   1291  1.1  scottr iwmDelay:
   1292  1.1  scottr 	/* TimeDBRA is ~8K for 040/33 machines, so we need nested loops */
   1293  1.3     chs id00:	movew	_C_LABEL(TimeDBRA),%d1	| dbra loops per ms
   1294  1.3     chs id01:	dbra	%d1,id01		|
   1295  1.3     chs 	dbra	%d0,id00
   1296  1.1  scottr 	rts
   1297  1.1  scottr 
   1298  1.1  scottr 
   1299  1.1  scottr /*
   1300  1.1  scottr  * selDriveReg -- Select drive status/control register
   1301  1.1  scottr  *
   1302  1.3     chs  * Parameters:	%d0	register #
   1303  1.1  scottr  *			(bit 0 - CA2, bit 1 - SEL, bit 2 - CA0, bit 3 - CA1)
   1304  1.3     chs  *		%a0	IWM base address
   1305  1.3     chs  *		%a1	VIA base address
   1306  1.3     chs  * Returns:	%d0	register # (unchanged)
   1307  1.1  scottr  */
   1308  1.1  scottr selDriveReg:
   1309  1.3     chs 	tstb	%a0@(ph0H)		| default CA0 to 1 (says IM III)
   1310  1.3     chs 	tstb	%a0@(ph1H)		| default CA1 to 1
   1311  1.1  scottr 
   1312  1.3     chs 	btst	#0,%d0			| bit 0 set => CA2 on
   1313  1.1  scottr 	beq	se00
   1314  1.3     chs 	tstb	%a0@(ph2H)
   1315  1.1  scottr 	bra	se01
   1316  1.1  scottr se00:
   1317  1.3     chs 	tstb	%a0@(ph2L)
   1318  1.1  scottr 
   1319  1.1  scottr se01:
   1320  1.3     chs 	btst	#1,%d0			| bit 1 set => SEL on (VIA 1)
   1321  1.1  scottr 	beq	se02
   1322  1.3     chs 	bset	#vHeadSel,%a1@(vBufA)
   1323  1.1  scottr 	bra	se03
   1324  1.1  scottr se02:
   1325  1.3     chs 	bclr	#vHeadSel,%a1@(vBufA)
   1326  1.1  scottr 
   1327  1.1  scottr se03:
   1328  1.3     chs 	btst	#2,%d0			| bit 2 set => CA0 on
   1329  1.1  scottr 	bne	se04
   1330  1.3     chs 	tstb	%a0@(ph0L)
   1331  1.1  scottr 
   1332  1.1  scottr se04:
   1333  1.3     chs 	btst	#3,%d0			| bit 3 set => CA1 on
   1334  1.1  scottr 	bne	se05
   1335  1.3     chs 	tstb	%a0@(ph1L)
   1336  1.1  scottr se05:
   1337  1.1  scottr 	rts
   1338  1.1  scottr 
   1339  1.1  scottr 
   1340  1.1  scottr 
   1341  1.1  scottr /*
   1342  1.1  scottr  * dstatus -- check drive status (bit 7 - N flag) wrt. a previously
   1343  1.1  scottr  * set status tag.
   1344  1.1  scottr  *
   1345  1.3     chs  * Parameters:	%d0	register selector
   1346  1.3     chs  *		%a0	IWM base address
   1347  1.3     chs  * Returns:	%d0	status
   1348  1.1  scottr  */
   1349  1.1  scottr dstatus:
   1350  1.3     chs 	tstb	%a0@(q6H)
   1351  1.3     chs 	moveb	%a0@(q7L),%d0
   1352  1.3     chs 	tstb	%a0@(q6L)		| leave in "read data reg"
   1353  1.3     chs 	tstb	%d0			| state for safety
   1354  1.1  scottr 	rts
   1355  1.1  scottr 
   1356  1.1  scottr 
   1357  1.1  scottr /*
   1358  1.1  scottr  * driveStat -- query drive status.
   1359  1.1  scottr  *
   1360  1.3     chs  * Parameters:	%a0	IWMBase
   1361  1.3     chs  *		%a1	VIABase
   1362  1.3     chs  *		%d0	register selector
   1363  1.3     chs  * Returns:	%d0	status (Bit 7)
   1364  1.1  scottr  */
   1365  1.1  scottr driveStat:
   1366  1.3     chs 	tstb	%a0@(mtrOn)		| ENABLE; turn drive on
   1367  1.1  scottr 	bsr	selDriveReg
   1368  1.1  scottr 	bsr	dstatus
   1369  1.1  scottr 	rts
   1370  1.1  scottr 
   1371  1.1  scottr 
   1372  1.1  scottr /*
   1373  1.1  scottr  * dtrigger -- toggle LSTRB line to give drive a strobe signal
   1374  1.1  scottr  * IM III says pulse length = 1 us < t < 1 ms
   1375  1.1  scottr  *
   1376  1.3     chs  * Parameters:	%a0	IWMBase
   1377  1.3     chs  *		%a1	VIABase
   1378  1.1  scottr  * Returns:	-
   1379  1.1  scottr  */
   1380  1.1  scottr dtrigger:
   1381  1.3     chs 	tstb	%a0@(ph3H)		| LSTRB high
   1382  1.3     chs 	moveb	%a1@(vBufA),%a1@(vBufA)	| intelligent nop seen in q700 ROM
   1383  1.3     chs 	tstb	%a0@(ph3L)		| LSTRB low
   1384  1.1  scottr 	rts
   1385  1.1  scottr 
   1386  1.1  scottr 
   1387  1.1  scottr /*
   1388  1.1  scottr  * driveCmd -- send command to drive.
   1389  1.1  scottr  *
   1390  1.3     chs  * Parameters:	%a0	IWMBase
   1391  1.3     chs  *		%a1	VIABase
   1392  1.3     chs  *		%d0	Command token
   1393  1.1  scottr  * Returns:	-
   1394  1.1  scottr  */
   1395  1.1  scottr driveCmd:
   1396  1.1  scottr 	bsr	selDriveReg
   1397  1.1  scottr 	bsr	dtrigger
   1398  1.1  scottr 	rts
   1399  1.1  scottr 
   1400  1.1  scottr 
   1401  1.1  scottr /*
   1402  1.1  scottr  * readSectHdr -- read and decode the next available sector header.
   1403  1.1  scottr  *
   1404  1.1  scottr  * TODO:	Poll SCC as long as interrupts are disabled.
   1405  1.1  scottr  *
   1406  1.3     chs  * Parameters:	%a4	sectorHdr_t address
   1407  1.3     chs  * Returns:	%d0	result code
   1408  1.3     chs  * Uses:	%d0-%d4, %a0, %a2-%a4
   1409  1.1  scottr  */
   1410  1.1  scottr readSectHdr:
   1411  1.3     chs 	moveq	#3,%d4			| Read 3 chars from IWM for sync
   1412  1.3     chs 	movew	#600,%d3		| Retries to sync to disk
   1413  1.3     chs 	moveq	#0,%d2			| Clear scratch regs
   1414  1.3     chs 	moveq	#0,%d1
   1415  1.3     chs 	moveq	#0,%d0
   1416  1.3     chs  	movel	_C_LABEL(IWMBase),%a0	| IWM base address
   1417  1.1  scottr 
   1418  1.3     chs 	tstb	%a0@(q7L)
   1419  1.3     chs 	lea	%a0@(q6L),%a0		| IWM data register
   1420  1.1  scottr shReadSy:
   1421  1.3     chs 	moveb	%a0@,%d2		| Read char
   1422  1.3     chs 	dbra	%d3,shSeekSync
   1423  1.1  scottr 
   1424  1.3     chs 	moveq	#noNybErr,%d0		| Disk is blank?
   1425  1.1  scottr 	bra	shDone
   1426  1.1  scottr 
   1427  1.1  scottr shSeekSync:
   1428  1.1  scottr 	bpl	shReadSy		| No char at IWM, repeat read
   1429  1.3     chs 	subqw	#1,%d4
   1430  1.1  scottr 	bne	shReadSy
   1431  1.1  scottr 	/*
   1432  1.1  scottr 	 * When we get here, the IWM should be in sync with the data
   1433  1.1  scottr 	 * stream from disk.
   1434  1.1  scottr 	 * Next look for sector header lead-in 'D5 AA 96'
   1435  1.1  scottr 	 */
   1436  1.3     chs 	movew	#1500,%d3		| Retries to seek header
   1437  1.1  scottr shLeadIn:
   1438  1.3     chs 	lea	hdrLeadIn,%a3		| Sector header lead-in bytes
   1439  1.3     chs 	moveq	#0x03,%d4		| is 3 bytes long
   1440  1.1  scottr shLI1:
   1441  1.3     chs 	moveb	%a0@,%d2		| Get next byte
   1442  1.2  scottr 	bpl	shLI1			| No char at IWM, repeat read
   1443  1.3     chs 	dbra	%d3,shLI2
   1444  1.3     chs 	moveq	#noAdrMkErr,%d0		| Can't find an address mark
   1445  1.1  scottr 	bra	shDone
   1446  1.1  scottr 
   1447  1.1  scottr shLI2:
   1448  1.3     chs 	cmpb	%a3@+,%d2
   1449  1.1  scottr 	bne	shLeadIn		| If ne restart scan
   1450  1.3     chs 	subqw	#1,%d4
   1451  1.1  scottr 	bne	shLI1
   1452  1.1  scottr 	/*
   1453  1.1  scottr 	 * We have found the lead-in. Now get the header information.
   1454  1.3     chs 	 * Reg %d4 holds the checksum.
   1455  1.1  scottr 	 */
   1456  1.3     chs 	lea	diskTo-0x90,%a2		| Translate disk bytes -> 6&2
   1457  1.1  scottr shHdr1:
   1458  1.3     chs 	moveb	%a0@,%d0		| Get 1st char
   1459  1.1  scottr 	bpl	shHdr1
   1460  1.3     chs 	moveb	%a2@(0,%d0),%d1		| and remap it
   1461  1.3     chs 	moveb	%d1,%d4
   1462  1.3     chs 	rorw	#6,%d1			| separate 2:6, drop hi bits
   1463  1.1  scottr shHdr2:
   1464  1.3     chs 	moveb	%a0@,%d0		| Get 2nd char
   1465  1.1  scottr 	bpl	shHdr2
   1466  1.3     chs 	moveb	%a2@(0,%d0),%d2		| and remap it
   1467  1.3     chs 	eorb	%d2,%d4
   1468  1.1  scottr shHdr3:
   1469  1.3     chs 	moveb	%a0@,%d0		| Get 3rd char
   1470  1.1  scottr 	bpl	shHdr3
   1471  1.3     chs 	moveb	%a2@(0,%d0),%d1		| and remap it
   1472  1.3     chs 	eorb	%d1,%d4
   1473  1.3     chs 	rolw	#6,%d1			|
   1474  1.1  scottr shHdr4:
   1475  1.3     chs 	moveb	%a0@,%d0		| Get 4th char
   1476  1.1  scottr 	bpl	shHdr4
   1477  1.3     chs 	moveb	%a2@(0,%d0),%d3		| and remap it
   1478  1.3     chs 	eorb	%d3,%d4
   1479  1.1  scottr shHdr5:
   1480  1.3     chs 	moveb	%a0@,%d0		| Get checksum byte
   1481  1.1  scottr 	bpl	shHdr5
   1482  1.3     chs 	moveb	%a2@(0,%d0),%d5		| and remap it
   1483  1.3     chs 	eorb	%d5,%d4
   1484  1.1  scottr 	bne	shCsErr			| Checksum ok?
   1485  1.1  scottr 	/*
   1486  1.1  scottr 	 * We now have in
   1487  1.3     chs 	 * %d1/lsb	track number
   1488  1.3     chs 	 * %d1/msb	bit 3 is side bit
   1489  1.3     chs 	 * %d2		sector number
   1490  1.3     chs 	 * %d3		???
   1491  1.3     chs 	 * %d5		checksum (=0)
   1492  1.1  scottr 	 *
   1493  1.1  scottr 	 * Next check for lead-out.
   1494  1.1  scottr 	 */
   1495  1.3     chs 	moveq	#1,%d4			| is 2 bytes long
   1496  1.1  scottr shHdr6:
   1497  1.3     chs 	moveb	%a0@,%d0		| Get token
   1498  1.1  scottr 	bpl	shHdr6
   1499  1.3     chs 	cmpb	%a3@+,%d0		| Check
   1500  1.1  scottr 	bne	shLOErr			| Fault!
   1501  1.3     chs 	dbra	%d4,shHdr6
   1502  1.3     chs 	movew	%d1,%d0			| Isolate side bit
   1503  1.3     chs 	lsrw	#8,%d0
   1504  1.3     chs 	moveb	%d0,%a4@+		| and store it
   1505  1.3     chs 	moveb	%d1,%a4@+		| Store track number
   1506  1.3     chs 	moveb	%d2,%a4@+		| and sector number
   1507  1.3     chs 	moveq	#0,%d0			| All is well
   1508  1.1  scottr 	bra	shDone
   1509  1.1  scottr 
   1510  1.1  scottr shCsErr:
   1511  1.3     chs 	moveq	#badCkSmErr,%d0		| Bad sector header checksum
   1512  1.1  scottr 	bra	shDone
   1513  1.1  scottr shLOErr:
   1514  1.3     chs 	moveq	#badBtSlpErr,%d0	| Bad address mark (no lead-out)
   1515  1.1  scottr 
   1516  1.1  scottr shDone:
   1517  1.3     chs 	tstl	%d0			| Set flags
   1518  1.1  scottr 	rts
   1519