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