Home | History | Annotate | Line # | Download | only in obio
iwm.s revision 1.2.26.2
      1  1.2.26.2  nathanw /*	$NetBSD: iwm.s,v 1.2.26.2 2002/09/17 21:15:32 nathanw 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.2.26.1  nathanw 	.extern	_C_LABEL(TimeDBRA)	| in mac68k/macrom.c
     77  1.2.26.1  nathanw 	.extern _C_LABEL(Via1Base)	| in mac68k/machdep.c
     78  1.2.26.1  nathanw 	.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.2.26.1  nathanw  *	%a0	IWM base address
    149  1.2.26.1  nathanw  *	%a1	VIA1 base address
    150       1.1   scottr  *
    151  1.2.26.1  nathanw  *	%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.2.26.1  nathanw  * Returns:	%d0		flag
    170       1.1   scottr  */
    171       1.1   scottr ENTRY(iwmQueryDrvFlag)
    172  1.2.26.1  nathanw 	link	%a6,#0
    173  1.2.26.1  nathanw 	moveml	%d1/%a0-%a1,%sp@-
    174  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    175  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    176       1.1   scottr 
    177  1.2.26.1  nathanw 	movel	%a6@(8),%d0		| Get drive #
    178       1.1   scottr 	beq	quDrv00
    179  1.2.26.1  nathanw 	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.2.26.1  nathanw 	tstb	%a0@(intDrive)		| SELECT; choose drive #0
    186       1.1   scottr 	bra	queryDrv
    187       1.1   scottr 
    188       1.1   scottr quDrv01:
    189  1.2.26.1  nathanw 	tstb	%a0@(extDrive)		| SELECT; choose drive #1
    190       1.1   scottr 
    191       1.1   scottr queryDrv:
    192  1.2.26.1  nathanw 	movel	%a6@(12),%d0		| Get register #
    193       1.1   scottr 	bsr	driveStat
    194       1.1   scottr 
    195       1.1   scottr quDone:
    196  1.2.26.1  nathanw 	moveml	%sp@+,%d1/%a0-%a1
    197  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Returns:	%d0		result code
    209       1.1   scottr  */
    210       1.1   scottr ENTRY(iwmReadSectHdr)
    211  1.2.26.1  nathanw 	link	%a6,#0
    212  1.2.26.1  nathanw 	moveml	%d1-%d5/%a0-%a4,%sp@-
    213  1.2.26.1  nathanw 	movel	%a6@(0x08),%a4		| Get param block address
    214       1.1   scottr 	bsr	readSectHdr
    215  1.2.26.1  nathanw 	moveml	%sp@+,%d1-%d5/%a0-%a4
    216  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Returns:	%d0		result code
    230       1.1   scottr  */
    231       1.1   scottr ENTRY(iwmInit)
    232  1.2.26.1  nathanw 	link	%a6,#0
    233  1.2.26.1  nathanw 	moveml	%d2/%a0,%sp@-
    234  1.2.26.1  nathanw 	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.2.26.1  nathanw 	tstb	%a0@(ph0L)		| CA0
    240  1.2.26.1  nathanw 	tstb	%a0@(ph1L)		| CA1
    241  1.2.26.1  nathanw 	tstb	%a0@(ph2L)		| CA2
    242  1.2.26.1  nathanw 	tstb	%a0@(ph3L)		| LSTRB
    243  1.2.26.1  nathanw 
    244  1.2.26.1  nathanw 	tstb	%a0@(mtrOff)		| ENABLE; make sure drive is off
    245  1.2.26.1  nathanw 	tstb	%a0@(intDrive)		| SELECT; choose drive 1
    246  1.2.26.1  nathanw 	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.2.26.1  nathanw 	tstb	%a0@(q6H)
    252  1.2.26.1  nathanw 	andb	%a0@(q7L),%d0		| status register
    253  1.2.26.1  nathanw 	tstb	%a0@(q6L)
    254  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movel	#0x00080000,%d2		| ca. 500,000 retries = 1.5 sec
    262       1.1   scottr initLp:
    263  1.2.26.1  nathanw 	moveq	#initIWMErr,%d0		| Initialization error
    264  1.2.26.1  nathanw 	subql	#1,%d2
    265       1.1   scottr 	bmi	initErr
    266  1.2.26.1  nathanw 	tstb	%a0@(mtrOff)		| disable drive
    267  1.2.26.1  nathanw 	tstb	%a0@(q6H)
    268  1.2.26.1  nathanw 	moveq	#0x3F,%d0
    269  1.2.26.1  nathanw 	andb	%a0@(q7L),%d0
    270  1.2.26.1  nathanw 	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.2.26.1  nathanw 	cmpib	#iwmMode,%d0
    274       1.1   scottr 	beq	initDone
    275  1.2.26.1  nathanw 	moveb	#iwmMode,%a0@(q7H)	| Init IWM
    276  1.2.26.1  nathanw 	tstb	%a0@(q7L)
    277       1.1   scottr 	bra	initLp
    278       1.1   scottr 
    279       1.1   scottr initDone:
    280  1.2.26.1  nathanw 	tstb	%a0@(q6L)		| Prepare IWM for data
    281  1.2.26.1  nathanw 	moveq	#0,%d0			| noErr
    282       1.1   scottr 
    283       1.1   scottr initErr:
    284  1.2.26.1  nathanw 	moveml	%sp@+,%d2/%a0
    285  1.2.26.1  nathanw 	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.2.26.1  nathanw  * 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.2.26.1  nathanw 	link	%a6,#0
    303  1.2.26.1  nathanw 	moveml	%d1/%a0-%a1,%sp@-
    304  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    305  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    306       1.1   scottr 
    307  1.2.26.1  nathanw 	moveq	#-1,%d1			| no drive
    308       1.1   scottr 
    309  1.2.26.1  nathanw 	movel	%a6@(0x08),%d0		| check drive #
    310       1.1   scottr 	beq	chkDrv00
    311  1.2.26.1  nathanw 	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.2.26.1  nathanw 	tstb	%a0@(intDrive)		| SELECT; choose drive #0
    318       1.1   scottr 	bra	chkDrive
    319       1.1   scottr 
    320       1.1   scottr chkDrv01:
    321  1.2.26.1  nathanw 	tstb	%a0@(extDrive)		| SELECT; choose drive #1
    322       1.1   scottr 
    323       1.1   scottr chkDrive:
    324  1.2.26.1  nathanw 	moveq	#-2,%d1			| error code
    325  1.2.26.1  nathanw 	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.2.26.1  nathanw 	moveq	#0,%d1			| Drive found
    330  1.2.26.1  nathanw 	tstb	%a0@(mtrOn)		| ENABLE; activate drive
    331  1.2.26.1  nathanw 	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.2.26.1  nathanw 	bset	#0,%d1			| 1 = no.
    342       1.1   scottr chkHasDisk:
    343  1.2.26.1  nathanw 	moveq	#diskInserted,%d0	| Disk inserted?
    344       1.1   scottr 	bsr	driveStat
    345       1.1   scottr 	bpl	chkMotorOn
    346  1.2.26.1  nathanw 	bset	#1,%d1			| 1 = No.
    347       1.1   scottr 	bra	chkDone
    348       1.1   scottr chkMotorOn:
    349  1.2.26.1  nathanw 	moveq	#drvMotorState,%d0	| Motor is running?
    350       1.1   scottr 	bsr	driveStat
    351       1.1   scottr 	bpl	chkWrtProt
    352  1.2.26.1  nathanw 	bset	#2,%d1			| 1 = No.
    353       1.1   scottr chkWrtProt:
    354  1.2.26.1  nathanw 	moveq	#writeProtected,%d0	| Disk is write protected?
    355       1.1   scottr 	bsr	driveStat
    356       1.1   scottr 	bpl	chkDD_HD
    357  1.2.26.1  nathanw 	bset	#3,%d1			| 1 = No.
    358       1.1   scottr chkDD_HD:
    359  1.2.26.1  nathanw 	moveq	#diskIsHD,%d0		| Disk is HD? (was "drive installed")
    360       1.1   scottr 	bsr	driveStat
    361       1.1   scottr 	bpl	chkDone
    362  1.2.26.1  nathanw 	bset	#4,%d1			| 1 = No.
    363       1.1   scottr chkDone:
    364  1.2.26.1  nathanw 	movel	%d1,%d0
    365  1.2.26.1  nathanw 	moveml	%sp@+,%d1/%a0-%a1
    366  1.2.26.1  nathanw 	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.2.26.1  nathanw  *		%a0		IWMBase
    378  1.2.26.1  nathanw  *		%a1		VIABase
    379  1.2.26.1  nathanw  * Returns:	%d0		result code
    380       1.1   scottr  */
    381       1.1   scottr ENTRY(iwmDiskEject)
    382  1.2.26.1  nathanw 	link	%a6,#0
    383  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    384  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    385       1.1   scottr 
    386  1.2.26.1  nathanw 	movel	%a6@(0x08),%d0		| Get drive #
    387       1.1   scottr 	beq	ejDrv00
    388  1.2.26.1  nathanw 	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.2.26.1  nathanw 	tstb	%a0@(intDrive)		| SELECT; choose drive #0
    395       1.1   scottr 	bra	ejDisk
    396       1.1   scottr 
    397       1.1   scottr ejDrv01:
    398  1.2.26.1  nathanw 	tstb	%a0@(extDrive)		| SELECT; choose drive #1
    399       1.1   scottr ejDisk:
    400  1.2.26.1  nathanw 	tstb	%a0@(mtrOn)		| ENABLE; activate drive
    401       1.1   scottr 
    402  1.2.26.1  nathanw 	moveq	#motorOffCmd,%d0	| Motor off
    403       1.1   scottr  	bsr	driveCmd
    404       1.1   scottr 
    405  1.2.26.1  nathanw 	moveq	#diskInserted,%d0	| Disk inserted?
    406       1.1   scottr 	bsr	driveStat
    407       1.1   scottr 	bmi	ejDone
    408       1.1   scottr 
    409  1.2.26.1  nathanw 	moveq	#ejectDiskCmd,%d0	| Eject it
    410       1.1   scottr 	bsr	selDriveReg
    411       1.1   scottr 
    412  1.2.26.1  nathanw 	tstb	%a0@(ph3H)		| LSTRB high
    413       1.1   scottr #if USE_DELAY
    414  1.2.26.1  nathanw 	movel	#1000,%sp@-		| delay 1 ms
    415       1.1   scottr 	jsr	_C_LABEL(delay)
    416  1.2.26.1  nathanw 	addqw	#4,%sp			| clean up stack
    417       1.1   scottr #else
    418  1.2.26.1  nathanw 	movew	#1,%d0
    419       1.1   scottr 	bsr	iwmDelay
    420       1.1   scottr #endif
    421  1.2.26.1  nathanw 	tstb	%a0@(ph3L)		| LSTRB low
    422  1.2.26.1  nathanw 	moveq	#0,%d0			| All's well...
    423       1.1   scottr ejDone:
    424  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Returns:	%d0		drive #
    433       1.1   scottr  */
    434       1.1   scottr ENTRY(iwmSelectDrive)
    435  1.2.26.1  nathanw 	link	%a6,#0
    436  1.2.26.1  nathanw 	moveml	%a0-%a1,%sp@-
    437  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    438  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    439       1.1   scottr 
    440  1.2.26.1  nathanw 	movel	%a6@(8),%d0		| Get drive #
    441       1.1   scottr 	bne	extDrv
    442  1.2.26.1  nathanw 	tstb	%a0@(intDrive)
    443       1.1   scottr 	bra	sdDone
    444       1.1   scottr extDrv:
    445  1.2.26.1  nathanw 	tstb	%a0@(extDrive)
    446       1.1   scottr sdDone:
    447  1.2.26.1  nathanw 	moveml	%sp@+,%a0-%a1
    448  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Returns:	%d0		motor cmd
    458       1.1   scottr  */
    459       1.1   scottr ENTRY(iwmMotor)
    460  1.2.26.1  nathanw 	link	%a6,#0
    461  1.2.26.1  nathanw 	moveml	%a0-%a1,%sp@-
    462  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    463  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    464       1.1   scottr 
    465  1.2.26.1  nathanw 	movel	%a6@(8),%d0		| Get drive #
    466       1.1   scottr 	bne	mtDrv1
    467  1.2.26.1  nathanw 	tstb	%a0@(intDrive)
    468       1.1   scottr 	bra	mtSwitch
    469       1.1   scottr mtDrv1:
    470  1.2.26.1  nathanw 	tstb	%a0@(extDrive)
    471       1.1   scottr mtSwitch:
    472  1.2.26.1  nathanw 	movel	#motorOnCmd,%d0		| Motor ON
    473  1.2.26.1  nathanw 	tstl	%a6@(12)
    474       1.1   scottr 	bne	mtON
    475  1.2.26.1  nathanw 	movel	#motorOffCmd,%d0
    476       1.1   scottr mtON:
    477       1.1   scottr 	bsr	driveCmd
    478       1.1   scottr 
    479  1.2.26.1  nathanw 	moveml	%sp@+,%a0-%a1
    480  1.2.26.1  nathanw 	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.2.26.1  nathanw 	link	%a6,#0
    494  1.2.26.1  nathanw 	moveml	%d1/%a0-%a1,%sp@-
    495  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    496  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    497       1.1   scottr 
    498  1.2.26.1  nathanw 	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.2.26.1  nathanw 	moveq	#rdDataFrom0,%d0	| Lower head
    505  1.2.26.1  nathanw 	movel	%a6@(0x08),%d1		| Get side #
    506       1.1   scottr 	beq	ssSide0
    507  1.2.26.1  nathanw 	moveq	#rdDataFrom1,%d0	| Upper head
    508       1.1   scottr ssSide0:
    509       1.1   scottr 	bsr	driveStat
    510       1.1   scottr 
    511  1.2.26.1  nathanw 	moveml	%sp@+,%d1/%a0-%a1
    512  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Returns:	%d0		result code
    523       1.1   scottr  */
    524       1.1   scottr ENTRY(iwmTrack00)
    525  1.2.26.1  nathanw 	link	%a6,#0
    526  1.2.26.1  nathanw 	moveml	%d1-%d4/%a0-%a1,%sp@-
    527  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    528  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    529       1.1   scottr 
    530  1.2.26.1  nathanw 	moveq	#motorOnCmd,%d0		| Switch drive motor on
    531       1.1   scottr 	bsr	driveCmd
    532       1.1   scottr 
    533  1.2.26.1  nathanw 	moveq	#stepOutCmd,%d0		| Step out
    534       1.1   scottr 	bsr	driveCmd
    535       1.1   scottr 
    536  1.2.26.1  nathanw 	movew	#100,%d2		| Max. tries
    537       1.1   scottr t0Retry:
    538  1.2.26.1  nathanw 	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.2.26.1  nathanw 	moveq	#doStepCmd,%d0		| otherwise step
    543       1.1   scottr 	bsr	driveCmd
    544  1.2.26.1  nathanw 	movew	#80,%d4			| Retries
    545       1.1   scottr t0Still:
    546  1.2.26.1  nathanw 	moveq	#stillStepping,%d0	| Drive is still stepping?
    547       1.1   scottr 	bsr	driveStat
    548  1.2.26.1  nathanw 	dbmi	%d4,t0Still
    549       1.1   scottr 
    550  1.2.26.1  nathanw 	cmpiw	#-1,%d4
    551       1.1   scottr 	bne	t002
    552       1.1   scottr 
    553  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movel	#15000,%sp@-
    559       1.1   scottr 	jsr	_C_LABEL(delay)		| in mac68k/clock.c
    560  1.2.26.1  nathanw 	addqw	#4,%sp
    561       1.1   scottr #else
    562  1.2.26.1  nathanw 	movew	#15,%d0
    563       1.1   scottr 	bsr	iwmDelay
    564       1.1   scottr #endif
    565       1.1   scottr 
    566  1.2.26.1  nathanw 	dbra	%d2,t0Retry
    567       1.1   scottr 
    568  1.2.26.1  nathanw 	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.2.26.1  nathanw 	moveq	#0,%d0
    573       1.1   scottr t0Done:
    574  1.2.26.1  nathanw 	moveml	%sp@+,%d1-%d4/%a0-%a1
    575  1.2.26.1  nathanw 	unlk	%a6
    576  1.2.26.1  nathanw 	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.2.26.1  nathanw  * returns:	%d0		result code
    584       1.1   scottr  */
    585       1.1   scottr ENTRY(iwmSeek)
    586  1.2.26.1  nathanw 	link	%a6,#0
    587  1.2.26.1  nathanw 	moveml	%d1-%d4/%a0-%a1,%sp@-
    588  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
    589  1.2.26.1  nathanw 	movel	_C_LABEL(Via1Base),%a1
    590       1.1   scottr 
    591  1.2.26.1  nathanw 	moveq	#motorOnCmd,%d0		| Switch drive motor on
    592       1.1   scottr 	bsr	driveCmd
    593       1.1   scottr 
    594  1.2.26.1  nathanw 	moveq	#stepInCmd,%d0		| Set step IN
    595  1.2.26.1  nathanw 	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.2.26.1  nathanw 	moveq	#stepOutCmd,%d0		| Set step OUT
    600  1.2.26.1  nathanw 	negl	%d2			| Make # of steps positive
    601       1.1   scottr stepOut:
    602  1.2.26.1  nathanw 	subql	#1,%d2			| Loop exits for -1
    603       1.1   scottr 	bsr	driveCmd		| Set direction
    604       1.1   scottr stLoop:
    605  1.2.26.1  nathanw 	moveq	#doStepCmd,%d0
    606       1.1   scottr 	bsr	driveCmd		| Step one!
    607  1.2.26.1  nathanw 	movew	#80,%d4			| Retries
    608       1.1   scottr st01:
    609  1.2.26.1  nathanw 	moveq	#stillStepping, %d0	| Drive is still stepping?
    610       1.1   scottr 	bsr	driveStat
    611  1.2.26.1  nathanw 	dbmi	%d4,st01
    612       1.1   scottr 
    613  1.2.26.1  nathanw 	cmpiw	#-1,%d4
    614       1.1   scottr 	bne	st02
    615       1.1   scottr 
    616  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movel	#30,%sp@-
    622       1.1   scottr 	jsr	_C_LABEL(delay)		| in mac68k/clock.c
    623  1.2.26.1  nathanw 	addqw	#4,%sp
    624       1.1   scottr #else
    625  1.2.26.1  nathanw 	movew	_C_LABEL(TimeDBRA),%d4	| dbra loops per ms
    626  1.2.26.1  nathanw 	lsrw	#5,%d4			| DIV 32
    627  1.2.26.1  nathanw st03:	dbra	%d4,st03		| makes ca. 30 us
    628       1.1   scottr #endif
    629       1.1   scottr 
    630  1.2.26.1  nathanw 	dbra	%d2,stLoop
    631       1.1   scottr 
    632  1.2.26.1  nathanw 	moveq	#0,%d2			| All is well
    633       1.1   scottr stDone:
    634  1.2.26.1  nathanw 	movel	%d2,%d0
    635  1.2.26.1  nathanw 	moveml	%sp@+,%d1-%d4/%a0-%a1
    636  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%fp+08	l	Address of sector data buffer (512 bytes)
    650  1.2.26.1  nathanw  *		%fp+12	l	Address of sector header struct (I/O)
    651  1.2.26.1  nathanw  *		%fp+16	l	Address of cache buffer ptr array
    652  1.2.26.1  nathanw  * Returns:	%d0		result code
    653  1.2.26.1  nathanw  * Local:	%fp-2	w	CPU status register
    654  1.2.26.1  nathanw  *		%fp-3	b	side,
    655  1.2.26.1  nathanw  *		%fp-4	b	track,
    656  1.2.26.1  nathanw  *		%fp-5	b	sector wanted
    657  1.2.26.1  nathanw  *		%fp-6	b	retry count
    658  1.2.26.1  nathanw  *		%fp-7	b	sector read
    659       1.1   scottr  */
    660       1.1   scottr ENTRY(iwmReadSector)
    661  1.2.26.1  nathanw 	link	%a6,#-8
    662  1.2.26.1  nathanw 	moveml	%d1-%d7/%a0-%a5,%sp@-
    663       1.1   scottr 
    664  1.2.26.1  nathanw  	movel	_C_LABEL(Via1Base),%a1
    665  1.2.26.1  nathanw 	movel	%a6@(o_hdr),%a4		| Addr of sector header struct
    666       1.1   scottr 
    667  1.2.26.1  nathanw 	moveb	%a4@+,%a6@(-3)		| Save side bit,
    668  1.2.26.1  nathanw 	moveb	%a4@+,%a6@(-4)		| track#,
    669  1.2.26.1  nathanw 	moveb	%a4@,%a6@(-5)		| sector#
    670  1.2.26.1  nathanw 	moveb	#2*maxGCRSectors,%a6@(-6) | Max. retry count
    671       1.1   scottr 
    672  1.2.26.1  nathanw 	movew	%sr,%a6@(-2)		| Save CPU status register
    673  1.2.26.1  nathanw 	oriw	#0x0600,%sr		| Block all interrupts
    674       1.1   scottr 
    675       1.2   scottr rsNextSect:
    676  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movel	%a6@(o_hdr),%a4		| Sector header struct
    684       1.1   scottr 
    685  1.2.26.1  nathanw 	moveb	%a4@(o_side),%d1	| Get actual side
    686  1.2.26.1  nathanw 	lsrb	#3,%d1			| "Normalize" side bit (to bit 0)
    687  1.2.26.1  nathanw 	andb	#1,%d1
    688  1.2.26.1  nathanw 	moveb	%a6@(-3),%d2		| Get wanted side
    689  1.2.26.1  nathanw 	eorb	%d1,%d2			| Compare side bits
    690       1.1   scottr 	bne	rsSeekErr		| Should be equal!
    691       1.1   scottr 
    692  1.2.26.1  nathanw 	moveb	%a6@(-4),%d1		| Get track# we want
    693  1.2.26.1  nathanw 	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.2.26.1  nathanw 	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.2.26.1  nathanw 	 *	%a0 points to data register of IWM as set up by readSectHdr
    704  1.2.26.1  nathanw 	 *	%a2 points to 'diskTo' translation table
    705  1.2.26.1  nathanw 	 *	%a4 points to tags buffer
    706       1.1   scottr 	 */
    707       1.1   scottr rsGetSect:
    708  1.2.26.1  nathanw 	moveb	%a4@(2),%a6@(-7)	| save sector number
    709  1.2.26.1  nathanw 	lea	%a4@(3),%a4		| Beginning of tag buffer
    710  1.2.26.1  nathanw 	moveq	#50,%d3			| Max. retries for sector lookup
    711       1.1   scottr rsLeadIn:
    712  1.2.26.1  nathanw 	lea	dataLeadIn,%a3		| Sector data lead-in
    713  1.2.26.1  nathanw 	moveq	#0x03,%d4		| is 3 bytes long
    714       1.1   scottr rsLI1:
    715  1.2.26.1  nathanw 	moveb	%a0@,%d2		| Get next byte
    716       1.1   scottr 	bpl	rsLI1
    717  1.2.26.1  nathanw 	dbra	%d3,rsLI2
    718  1.2.26.1  nathanw 	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.2.26.1  nathanw 	cmpb	%a3@+,%d2
    723       1.1   scottr 	bne	rsLeadIn		| If ne restart scan
    724  1.2.26.1  nathanw 	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.2.26.1  nathanw 	 * (We leave %a3 pointing to 'dataLeadOut' for later.)
    730       1.1   scottr 	 */
    731       1.1   scottr rsTagNyb0:
    732  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get a char,
    733       1.1   scottr 	bpl	rsTagNyb0
    734  1.2.26.1  nathanw 	moveb	%a2@(0,%d3),%a4@+	| remap and store it
    735       1.1   scottr 
    736  1.2.26.1  nathanw 	moveq	#0,%d5			| Clear checksum registers
    737  1.2.26.1  nathanw 	moveq	#0,%d6
    738  1.2.26.1  nathanw 	moveq	#0,%d7
    739  1.2.26.1  nathanw 	moveq	#10,%d4			| Loop counter
    740  1.2.26.1  nathanw 	moveq	#0,%d3			| Data scratch reg
    741       1.1   scottr 
    742       1.1   scottr rsTags:
    743       1.1   scottr rsTagNyb1:
    744  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get 2 bit nibbles
    745       1.1   scottr 	bpl	rsTagNyb1
    746  1.2.26.1  nathanw 	moveb	%a2@(0,%d3),%d1		| Remap disk byte
    747  1.2.26.1  nathanw 	rolb	#2,%d1
    748  1.2.26.1  nathanw 	moveb	%d1,%d2
    749  1.2.26.1  nathanw 	andib	#0xC0,%d2		| Get top 2 bits for first byte
    750       1.1   scottr rsTagNyb2:
    751  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get first 6 bit nibble
    752       1.1   scottr 	bpl	rsTagNyb2
    753  1.2.26.1  nathanw 	orb	%a2@(0,%d3),%d2		| Remap it and complete first byte
    754       1.1   scottr 
    755  1.2.26.1  nathanw 	moveb	%d7,%d3			| The X flag bit (a copy of the carry
    756  1.2.26.1  nathanw 	addb	%d7,%d3			| flag) is added with the next addx
    757       1.1   scottr 
    758  1.2.26.1  nathanw 	rolb	#1,%d7
    759  1.2.26.1  nathanw 	eorb	%d7,%d2
    760  1.2.26.1  nathanw 	moveb	%d2,%a4@+		| Store tag byte
    761  1.2.26.1  nathanw 	addxb	%d2,%d5			| See above
    762  1.2.26.1  nathanw 
    763  1.2.26.1  nathanw 	rolb	#2,%d1
    764  1.2.26.1  nathanw 	moveb	%d1,%d2
    765  1.2.26.1  nathanw 	andib	#0xC0,%d2		| Get top 2 bits for second byte
    766       1.1   scottr rsTagNyb3:
    767  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get second 6 bit nibble
    768       1.1   scottr 	bpl	rsTagNyb3
    769  1.2.26.1  nathanw 	orb	%a2@(0,%d3),%d2		| remap it and complete byte
    770  1.2.26.1  nathanw 	eorb	%d5,%d2
    771  1.2.26.1  nathanw 	moveb	%d2,%a4@+		| Store tag byte
    772  1.2.26.1  nathanw 	addxb	%d2,%d6
    773       1.1   scottr 
    774  1.2.26.1  nathanw 	rolb	#2,%d1
    775  1.2.26.1  nathanw 	andib	#0xC0,%d1		| Get top 2 bits for third byte
    776       1.1   scottr rsTagNyb4:
    777  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get third 6 bit nibble
    778       1.1   scottr 	bpl	rsTagNyb4
    779  1.2.26.1  nathanw 	orb	%a2@(0,%d3),%d1		| remap it and complete byte
    780  1.2.26.1  nathanw 	eorb	%d6,%d1
    781  1.2.26.1  nathanw 	moveb	%d1,%a4@+		| Store tag byte
    782  1.2.26.1  nathanw 	addxb	%d1,%d7
    783       1.1   scottr 
    784  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movew	#0x01FE,%d4		| Loop counter
    796  1.2.26.1  nathanw 	moveq	#0,%d1			| Clear %d1
    797  1.2.26.1  nathanw 	moveb	%a6@(-7),%d1		| Get sector# we have read
    798  1.2.26.1  nathanw 	cmpb	%a6@(-5),%d1		| Compare to the sector# we want
    799       1.2   scottr 	bne	rsToCache
    800  1.2.26.1  nathanw 	movel	%a6@(o_buf),%a4		| Sector data buffer
    801       1.2   scottr 	bra	rsData
    802       1.2   scottr rsToCache:
    803  1.2.26.1  nathanw 	movel	%a6@(o_rslots),%a4	| Base address of slot array
    804  1.2.26.1  nathanw 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
    805  1.2.26.1  nathanw 	movel	#-1,%a4@(o_valid,%d1)
    806  1.2.26.1  nathanw 	movel	%a4@(o_secbuf,%d1),%a4	| and get its buffer ptr
    807       1.1   scottr rsData:
    808       1.1   scottr rsDatNyb1:
    809  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get 2 bit nibbles
    810       1.1   scottr 	bpl	rsDatNyb1
    811  1.2.26.1  nathanw 	moveb	%a2@(0,%d3),%d1		| Remap disk byte
    812  1.2.26.1  nathanw 	rolb	#2,%d1
    813  1.2.26.1  nathanw 	moveb	%d1,%d2
    814  1.2.26.1  nathanw 	andib	#0xC0,%d2		| Get top 2 bits for first byte
    815       1.1   scottr rsDatNyb2:
    816  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get first 6 bit nibble
    817       1.1   scottr 	bpl	rsDatNyb2
    818  1.2.26.1  nathanw 	orb	%a2@(0,%d3),%d2		| Remap it and complete first byte
    819       1.1   scottr 
    820  1.2.26.1  nathanw 	moveb	%d7,%d3			| The X flag bit (a copy of the carry
    821  1.2.26.1  nathanw 	addb	%d7,%d3			| flag) is added with the next addx
    822       1.1   scottr 
    823  1.2.26.1  nathanw 	rolb	#1,%d7
    824  1.2.26.1  nathanw 	eorb	%d7,%d2
    825  1.2.26.1  nathanw 	moveb	%d2,%a4@+		| Store data byte
    826  1.2.26.1  nathanw 	addxb	%d2,%d5			| See above
    827  1.2.26.1  nathanw 
    828  1.2.26.1  nathanw 	rolb	#2,%d1
    829  1.2.26.1  nathanw 	moveb	%d1,%d2
    830  1.2.26.1  nathanw 	andib	#0xC0,%d2		| Get top 2 bits for second byte
    831       1.1   scottr rsDatNyb3:
    832  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get second 6 bit nibble
    833       1.1   scottr 	bpl	rsDatNyb3
    834  1.2.26.1  nathanw 	orb	%a2@(0,%d3),%d2		| Remap it and complete byte
    835  1.2.26.1  nathanw 	eorb	%d5,%d2
    836  1.2.26.1  nathanw 	moveb	%d2,%a4@+		| Store data byte
    837  1.2.26.1  nathanw 	addxb	%d2,%d6
    838  1.2.26.1  nathanw 	tstw	%d4
    839       1.1   scottr 	beq	rsCkSum			| Data read, continue with checksums
    840       1.1   scottr 
    841  1.2.26.1  nathanw 	rolb	#2,%d1
    842  1.2.26.1  nathanw 	andib	#0xC0,%d1		| Get top 2 bits for third byte
    843       1.1   scottr rsDatNyb4:
    844  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get third 6 bit nibble
    845       1.1   scottr 	bpl	rsDatNyb4
    846  1.2.26.1  nathanw 	orb	%a2@(0,%d3),%d1		| Remap it and complete byte
    847  1.2.26.1  nathanw 	eorb	%d6,%d1
    848  1.2.26.1  nathanw 	moveb	%d1,%a4@+		| Store data byte
    849  1.2.26.1  nathanw 	addxb	%d1,%d7
    850  1.2.26.1  nathanw 	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.2.26.1  nathanw 	 * maintained in %D5/%D6/%D7 for the 1st/2nd/3rd data byte of
    857  1.2.26.1  nathanw 	 * each group.
    858       1.1   scottr 	 */
    859       1.1   scottr rsCkSum:
    860       1.1   scottr rsCkS1:
    861  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get 2 bit nibbles
    862       1.1   scottr 	bpl	rsCkS1
    863  1.2.26.1  nathanw 	moveb	%a2@(0,%d3),%d1		| Remap disk byte
    864       1.1   scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    865  1.2.26.1  nathanw 	rolb	#2,%d1
    866  1.2.26.1  nathanw 	moveb	%d1,%d2
    867  1.2.26.1  nathanw 	andib	#0xC0,%d2		| Get top 2 bits for first byte
    868       1.1   scottr rsCkS2:
    869  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get first 6 bit nibble
    870       1.1   scottr 	bpl	rsCkS2
    871  1.2.26.1  nathanw 	moveb	%a2@(0,%d3),%d3		| and remap it
    872       1.1   scottr 	bmi	rsBadCkSum		| Fault! ( > 0x3f is bad read)
    873  1.2.26.1  nathanw 	orb	%d3,%d2			| Merge 6&2
    874  1.2.26.1  nathanw 	cmpb	%d2,%d5			| Compare first checksum to %D5
    875       1.1   scottr 	bne	rsBadCkSum		| Fault! (Checksum)
    876       1.1   scottr 
    877  1.2.26.1  nathanw 	rolb	#2,%d1
    878  1.2.26.1  nathanw 	moveb	%d1,%d2
    879  1.2.26.1  nathanw 	andib	#0xC0,%d2		| Get top 2 bits for second byte
    880       1.1   scottr rsCkS3:
    881  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get second 6 bit nibble
    882       1.1   scottr 	bpl	rsCkS3
    883  1.2.26.1  nathanw 	moveb	%a2@(0,%d3),%d3		| and remap it
    884       1.1   scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    885  1.2.26.1  nathanw 	orb	%d3,%d2			| Merge 6&2
    886  1.2.26.1  nathanw 	cmpb	%d2,%d6			| Compare second checksum to %D6
    887       1.1   scottr 	bne	rsBadCkSum		| Fault! (Checksum)
    888       1.1   scottr 
    889  1.2.26.1  nathanw 	rolb	#2,%d1
    890  1.2.26.1  nathanw 	andib	#0xC0,%d1		| Get top 2 bits for second byte
    891       1.1   scottr rsCkS4:
    892  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get third 6 bit nibble
    893       1.1   scottr 	bpl	rsCkS4
    894  1.2.26.1  nathanw 	moveb	%a2@(0,%d3),%d3		| and remap it
    895       1.1   scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    896  1.2.26.1  nathanw 	orb	%d3,%d1			| Merge 6&2
    897  1.2.26.1  nathanw 	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.2.26.1  nathanw 	moveq	#badDCkSum,%d0		| Bad data mark checksum
    902       1.1   scottr 	bra	rsDone
    903       1.1   scottr 
    904       1.1   scottr rsBadDBtSlp:
    905  1.2.26.1  nathanw 	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.2.26.1  nathanw 	 * (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.2.26.1  nathanw 	moveq	#1,%d4			| Is two bytes long {1,0}
    916       1.1   scottr rsLdOut1:
    917  1.2.26.1  nathanw 	moveb	%a0@,%d3		| Get token
    918       1.1   scottr 	bpl	rsLdOut1
    919  1.2.26.1  nathanw 	cmpb	%a3@+,%d3
    920       1.1   scottr 	bne	rsBadDBtSlp		| Fault!
    921  1.2.26.1  nathanw 	dbra	%d4,rsLdOut1
    922  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movel	%a6@(o_hdr),%a4		| Addr of sector header struct
    931  1.2.26.1  nathanw 	moveb	%a4@(o_sector),%d1	| Get # of sector we have just read
    932  1.2.26.1  nathanw 	cmpb	%a6@(-5),%d1		| Compare to the sector we want
    933       1.2   scottr 	beq	rsAllDone
    934       1.2   scottr 
    935  1.2.26.1  nathanw 	tstb	%d0			| Any error? Simply ignore data
    936       1.2   scottr 	beq	rsBufValid
    937  1.2.26.1  nathanw 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
    938  1.2.26.1  nathanw 	movel	%a6@(o_rslots),%a4
    939  1.2.26.1  nathanw 	clrl	%a4@(o_valid,%d1)	| Mark buffer content "invalid"
    940       1.2   scottr 
    941       1.2   scottr rsBufValid:
    942  1.2.26.1  nathanw 	subqb	#1,%a6@(-6)		| max. retries
    943       1.2   scottr 	bne	rsNextSect
    944       1.2   scottr 					| Sector not found, but
    945  1.2.26.1  nathanw 	tstb	%d0			| don't set error code if we
    946       1.2   scottr 	bne	rsAllDone		| already have one.
    947  1.2.26.1  nathanw 	moveq	#sectNFErr,%d0
    948       1.2   scottr rsAllDone:
    949  1.2.26.1  nathanw 	movew	%a6@(-2),%sr		| Restore interrupt mask
    950  1.2.26.1  nathanw 	moveml	%sp@+,%d1-%d7/%a0-%a5
    951  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%fp+8	l	Address of sector header struct (I/O)
    964  1.2.26.1  nathanw  *		%fp+12	l	Address of cache buffer ptr array
    965  1.2.26.1  nathanw  * Returns:	%d0		result code
    966  1.2.26.1  nathanw  *
    967  1.2.26.1  nathanw  * Local:	%fp-2	w	CPU status register
    968  1.2.26.1  nathanw  *		%fp-3	b	side,
    969  1.2.26.1  nathanw  *		%fp-4	b	track,
    970  1.2.26.1  nathanw  *		%fp-5	b	sector wanted
    971  1.2.26.1  nathanw  *		%fp-6	b	retry count
    972  1.2.26.1  nathanw  *		%fp-10	b	current slot
    973       1.1   scottr  */
    974       1.1   scottr ENTRY(iwmWriteSector)
    975  1.2.26.1  nathanw 	link	%a6,#-10
    976  1.2.26.1  nathanw 	moveml	%d1-%d7/%a0-%a5,%sp@-
    977       1.1   scottr 
    978  1.2.26.1  nathanw  	movel	_C_LABEL(Via1Base),%a1
    979  1.2.26.1  nathanw 	movel	%a6@(o_hdr),%a4		| Addr of sector header struct
    980       1.1   scottr 
    981  1.2.26.1  nathanw 	moveb	%a4@+,%a6@(-3)		| Save side bit,
    982  1.2.26.1  nathanw 	moveb	%a4@+,%a6@(-4)		| track#,
    983  1.2.26.1  nathanw 	moveb	%a4@,%a6@(-5)		| sector#
    984  1.2.26.1  nathanw 	moveb	#maxGCRSectors,%a6@(-6)	| Max. retry count
    985       1.1   scottr 
    986  1.2.26.1  nathanw 	movew	%sr,%a6@(-2)		| Save CPU status register
    987  1.2.26.1  nathanw 	oriw	#0x0600,%sr		| Block all interrupts
    988       1.1   scottr 
    989       1.2   scottr wsNextSect:
    990  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movel	%a6@(o_hdr),%a4		| Sector header struct
    998       1.1   scottr 
    999  1.2.26.1  nathanw 	moveb	%a4@(o_side),%d1	| Get side#
   1000  1.2.26.1  nathanw 	lsrb	#3,%d1			| "Normalize" side bit...
   1001  1.2.26.1  nathanw 	andb	#1,%d1
   1002  1.2.26.1  nathanw 	moveb	%a6@(-3),%d2		| Get wanted side
   1003  1.2.26.1  nathanw 	eorb	%d1,%d2			| Compare side bits
   1004       1.1   scottr 	bne	wsSeekErr
   1005       1.1   scottr 
   1006  1.2.26.1  nathanw 	moveb	%a6@(-4),%d1		| Get wanted track#
   1007  1.2.26.1  nathanw 	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.2.26.1  nathanw 	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.2.26.1  nathanw 	moveq	#0,%d1			| Clear register
   1023  1.2.26.1  nathanw 	moveb	%a4@(o_sector),%d1	| get the # of header read
   1024  1.2.26.1  nathanw 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
   1025  1.2.26.1  nathanw 	movel	%a6@(o_wslots),%a4
   1026  1.2.26.1  nathanw 	tstl	%a4@(o_valid,%d1)	| Sector dirty?
   1027       1.2   scottr 	bne	wsBufDirty
   1028       1.2   scottr 
   1029  1.2.26.1  nathanw 	moveq	#maxGCRSectors-1,%d2	| Any dirty sectors left?
   1030       1.2   scottr wsChkDty:
   1031  1.2.26.1  nathanw 	movew	%d2,%d1
   1032  1.2.26.1  nathanw 	lslw	#3,%d1			| sizeof cylCacheSlot_t is 8 bytes
   1033  1.2.26.1  nathanw 	tstl	%a4@(o_valid,%d1)
   1034       1.2   scottr 	bne	wsNextSect		| Sector dirty?
   1035  1.2.26.1  nathanw 	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.2.26.1  nathanw 	 *	%a0	IWM base address (later: data register)
   1053  1.2.26.1  nathanw 	 *	%a1	Via1Base
   1054  1.2.26.1  nathanw 	 *	%a2	IWM handshake register
   1055  1.2.26.1  nathanw 	 *	%a3	data (tags buffer, data buffer)
   1056  1.2.26.1  nathanw 	 *	%a4	Sync pattern, 'toDisk' translation table
   1057       1.1   scottr 	 */
   1058       1.2   scottr wsBufDirty:
   1059  1.2.26.1  nathanw 	movel	_C_LABEL(IWMBase),%a0
   1060  1.2.26.1  nathanw 	lea	%a4@(0,%d1),%a3
   1061  1.2.26.1  nathanw 	movel	%a3,%a6@(-10)		| Save ptr to current slot
   1062  1.2.26.1  nathanw 	tstb	%a0@(q6H)		| Enable writing to disk
   1063  1.2.26.1  nathanw 	movel	%a6@(o_hdr),%a4		| Sector header struct
   1064  1.2.26.1  nathanw 	lea	%a4@(o_Tags),%a3	| Point %a3 to tags buffer
   1065  1.2.26.1  nathanw 	lea	syncPattern,%a4
   1066  1.2.26.1  nathanw 
   1067  1.2.26.1  nathanw 	moveb	%a4@+,%a0@(q7H)		| Write first sync byte
   1068  1.2.26.1  nathanw 	lea	%a0@(q6L),%a2		| Point %a2 to handshake register
   1069  1.2.26.1  nathanw 	lea	%a0@(q6H),%a0		| Point %a0 to IWM data register
   1070  1.2.26.1  nathanw 
   1071  1.2.26.1  nathanw 	moveq	#6,%d0			| Loop counter for sync bytes
   1072  1.2.26.1  nathanw 	moveq	#0,%d2
   1073  1.2.26.1  nathanw 	moveq	#0,%d3
   1074  1.2.26.1  nathanw 	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.2.26.1  nathanw 	moveb	%a4@+,%d1		| Get next sync byte
   1081       1.1   scottr wsLI1:
   1082  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1083       1.1   scottr 	bpl	wsLI1
   1084  1.2.26.1  nathanw 	moveb	%d1,%a0@		| Write it to disk
   1085  1.2.26.1  nathanw 	subqw	#1,%d0
   1086       1.1   scottr 	bne	wsLeadIn
   1087       1.1   scottr 
   1088  1.2.26.1  nathanw 	moveb	%a4@+,%d1		| Write 2nd byte of sector lead-in
   1089  1.2.26.1  nathanw 	lea	toDisk,%a4		| Point %a4 to nibble translation table
   1090       1.1   scottr wsLI2:
   1091  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1092       1.1   scottr 	bpl	wsLI2
   1093  1.2.26.1  nathanw 	moveb	%d1,%a0@		| Write it to disk
   1094       1.1   scottr 
   1095  1.2.26.1  nathanw 	moveq	#0,%d5			| Clear checksum registers
   1096  1.2.26.1  nathanw 	moveq	#0,%d6
   1097  1.2.26.1  nathanw 	moveq	#0,%d7
   1098       1.1   scottr 
   1099  1.2.26.1  nathanw 	moveq	#0x0B,%d1		| 3rd byte of sector data lead-in
   1100       1.1   scottr 					| (Gets translated to 0xAD)
   1101  1.2.26.1  nathanw 	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.2.26.1  nathanw 	movel	%a6@(-10),%a3		| Get ptr to current slot
   1122  1.2.26.1  nathanw 	movel	%a3@(o_secbuf),%a3	| Get start of sector data buffer
   1123       1.1   scottr 
   1124       1.1   scottr wsData:
   1125  1.2.26.1  nathanw 	addxb	%d2,%d7
   1126  1.2.26.1  nathanw 	eorb	%d6,%d2
   1127  1.2.26.1  nathanw 	moveb	%d2,%d3
   1128  1.2.26.1  nathanw 	lsrw	#6,%d3			| Put 2 bit nibbles into place
   1129       1.1   scottr wsRDY01:
   1130  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1131       1.1   scottr 	bpl	wsRDY01
   1132  1.2.26.1  nathanw 	moveb	%a4@(0,%d3),%a0@	| Translate nibble and write
   1133  1.2.26.1  nathanw 	subqw	#3,%d4			| Update counter
   1134  1.2.26.1  nathanw 	moveb	%d7,%d3
   1135  1.2.26.1  nathanw 	addb	%d7,%d3			| Set X flag (??)
   1136  1.2.26.1  nathanw 	rolb	#1,%d7
   1137  1.2.26.1  nathanw 	andib	#0x3F,%d0
   1138       1.1   scottr wsRDY02:
   1139  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1140       1.1   scottr 	bpl	wsRDY02
   1141  1.2.26.1  nathanw 	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.2.26.1  nathanw 	 * between our teeth (%D1, that is).
   1146       1.1   scottr 	 */
   1147       1.1   scottr wsDataEntry:
   1148  1.2.26.1  nathanw 	moveb	%a3@+,%d0		| Get first byte
   1149  1.2.26.1  nathanw 	addxb	%d0,%d5
   1150  1.2.26.1  nathanw 	eorb	%d7,%d0
   1151  1.2.26.1  nathanw 	moveb	%d0,%d3			| Keep top two bits
   1152  1.2.26.1  nathanw 	rolw	#2,%d3			| by shifting them to MSByte
   1153  1.2.26.1  nathanw 	andib	#0x3F,%d1
   1154       1.1   scottr wsRDY03:
   1155  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1156       1.1   scottr 	bpl	wsRDY03
   1157  1.2.26.1  nathanw 	moveb	%a4@(0,%d1),%a0@	| Translate nibble and write
   1158       1.1   scottr 
   1159  1.2.26.1  nathanw 	moveb	%a3@+,%d1			| Get second byte
   1160  1.2.26.1  nathanw 	addxb	%d1,%d6
   1161  1.2.26.1  nathanw 	eorb	%d5,%d1
   1162  1.2.26.1  nathanw 	moveb	%d1,%d3			| Keep top two bits
   1163  1.2.26.1  nathanw 	rolw	#2,%d3			| by shifting them to MSByte
   1164  1.2.26.1  nathanw 	andib	#0x3F,%d2
   1165       1.1   scottr wsRDY04:
   1166  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1167       1.1   scottr 	bpl	wsRDY04
   1168  1.2.26.1  nathanw 	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.2.26.1  nathanw 	tstl	%d4			| Last loop cycle?
   1178       1.1   scottr 	beq	wsSDDone		| Then get out while we can.
   1179       1.1   scottr 
   1180  1.2.26.1  nathanw 	moveb	%a3@+,%d2		| Get third byte
   1181  1.2.26.1  nathanw 	tstw	%d4			| First write tag buffer,...
   1182       1.1   scottr 	bne	wsData
   1183       1.1   scottr 
   1184  1.2.26.1  nathanw 	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.2.26.1  nathanw 	clrb	%d3			| No 513th byte
   1193  1.2.26.1  nathanw 	lsrw	#6,%d3			| Set up 2 bit nibbles
   1194       1.1   scottr wsRDY05:
   1195  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1196       1.1   scottr 	bpl	wsRDY05
   1197  1.2.26.1  nathanw 	moveb	%a4@(0,%d3),%a0@	| Write fragments
   1198  1.2.26.1  nathanw 	moveb	%d5,%d3
   1199  1.2.26.1  nathanw 	rolw	#2,%d3
   1200  1.2.26.1  nathanw 	moveb	%d6,%d3
   1201  1.2.26.1  nathanw 	rolw	#2,%d3
   1202  1.2.26.1  nathanw 	andib	#0x3F,%d0
   1203       1.1   scottr wsRDY06:
   1204  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1205       1.1   scottr 	bpl	wsRDY06
   1206  1.2.26.1  nathanw 	moveb	%a4@(0,%d0),%a0@	| Write 511th byte
   1207  1.2.26.1  nathanw 	andib	#0x3F,%d1
   1208       1.1   scottr wsRDY07:
   1209  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1210       1.1   scottr 	bpl	wsRDY07
   1211  1.2.26.1  nathanw 	moveb	%a4@(0,%d1),%a0@	| write 512th byte
   1212  1.2.26.1  nathanw 	moveb	%d7,%d3
   1213  1.2.26.1  nathanw 	lsrw	#6,%d3			| Get fragments ready
   1214       1.1   scottr wsRDY08:
   1215  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1216       1.1   scottr 	bpl	wsRDY08
   1217  1.2.26.1  nathanw 	moveb	%a4@(0,%d3),%a0@	| Write fragments
   1218  1.2.26.1  nathanw 	andib	#0x3F,%d5
   1219       1.1   scottr wsRDY09:
   1220  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1221       1.1   scottr 	bpl	wsRDY09
   1222  1.2.26.1  nathanw 	moveb	%a4@(0,%d5),%a0@	| Write first checksum byte
   1223  1.2.26.1  nathanw 	andib	#0x3F,%D6
   1224       1.1   scottr wsRDY10:
   1225  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1226       1.1   scottr 	bpl	wsRDY10
   1227  1.2.26.1  nathanw 	moveb	%a4@(0,%d6),%a0@	| Write second checksum byte
   1228  1.2.26.1  nathanw 	andib	#0x3F,%d7
   1229       1.1   scottr wsRDY11:
   1230  1.2.26.1  nathanw 	tstb	%a2@			| IWM ready?
   1231       1.1   scottr 	bpl	wsRDY11
   1232  1.2.26.1  nathanw 	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.2.26.1  nathanw 	lea	dataLeadOut,%a4		| Sector data lead-out
   1238  1.2.26.1  nathanw 	moveq	#3,%d2			| Four bytes long {3,2,1,0}
   1239       1.1   scottr wsLeadOut:
   1240  1.2.26.1  nathanw 	moveb	%a2@,%d1		| IWM ready?
   1241       1.1   scottr 	bpl	wsLeadOut
   1242  1.2.26.1  nathanw 	moveb	%a4@+,%a0@		| Write lead-out
   1243  1.2.26.1  nathanw 	dbf	%d2,wsLeadOut
   1244       1.1   scottr 
   1245  1.2.26.1  nathanw 	moveq	#0,%d0
   1246  1.2.26.1  nathanw 	btst	#6,%d1			| Check IWM underrun bit
   1247       1.1   scottr 	bne	wsNoErr
   1248       1.1   scottr 
   1249  1.2.26.1  nathanw 	moveq	#wrUnderRun,%d0		| Could not write
   1250       1.1   scottr 					| fast enough to keep up with IWM
   1251       1.1   scottr wsNoErr:
   1252  1.2.26.1  nathanw 	tstb	%a0@(0x0200)		| q7L -- Write OFF
   1253       1.1   scottr 
   1254       1.1   scottr wsDone:
   1255  1.2.26.1  nathanw 	tstb	%d0			| Any error? Simply retry
   1256       1.2   scottr 	bne	wsBufInvalid
   1257       1.2   scottr 
   1258  1.2.26.1  nathanw 	movel	%a6@(-10),%a4		| Else, get ptr to current slot
   1259  1.2.26.1  nathanw 	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.2.26.1  nathanw 	subqb	#1,%a6@(-6)		| retries
   1264       1.2   scottr 	bne	wsNextSect
   1265       1.2   scottr 					| Sector not found, but
   1266  1.2.26.1  nathanw 	tstb	%d0			| don't set error code if we
   1267       1.2   scottr 	bne	wsAllDone		| already have one.
   1268  1.2.26.1  nathanw 	moveq	#sectNFErr,%d0
   1269       1.2   scottr 
   1270       1.2   scottr wsAllDone:
   1271  1.2.26.1  nathanw 	movew	%a6@(-2),%sr		| Restore interrupt mask
   1272  1.2.26.1  nathanw 	moveml	%sp@+,%d1-%d7/%a0-%a5
   1273  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%d0	delay in milliseconds
   1288  1.2.26.1  nathanw  * 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.2.26.1  nathanw id00:	movew	_C_LABEL(TimeDBRA),%d1	| dbra loops per ms
   1294  1.2.26.1  nathanw id01:	dbra	%d1,id01		|
   1295  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%d0	register #
   1303       1.1   scottr  *			(bit 0 - CA2, bit 1 - SEL, bit 2 - CA0, bit 3 - CA1)
   1304  1.2.26.1  nathanw  *		%a0	IWM base address
   1305  1.2.26.1  nathanw  *		%a1	VIA base address
   1306  1.2.26.1  nathanw  * Returns:	%d0	register # (unchanged)
   1307       1.1   scottr  */
   1308       1.1   scottr selDriveReg:
   1309  1.2.26.1  nathanw 	tstb	%a0@(ph0H)		| default CA0 to 1 (says IM III)
   1310  1.2.26.1  nathanw 	tstb	%a0@(ph1H)		| default CA1 to 1
   1311       1.1   scottr 
   1312  1.2.26.1  nathanw 	btst	#0,%d0			| bit 0 set => CA2 on
   1313       1.1   scottr 	beq	se00
   1314  1.2.26.1  nathanw 	tstb	%a0@(ph2H)
   1315       1.1   scottr 	bra	se01
   1316       1.1   scottr se00:
   1317  1.2.26.1  nathanw 	tstb	%a0@(ph2L)
   1318       1.1   scottr 
   1319       1.1   scottr se01:
   1320  1.2.26.1  nathanw 	btst	#1,%d0			| bit 1 set => SEL on (VIA 1)
   1321       1.1   scottr 	beq	se02
   1322  1.2.26.1  nathanw 	bset	#vHeadSel,%a1@(vBufA)
   1323       1.1   scottr 	bra	se03
   1324       1.1   scottr se02:
   1325  1.2.26.1  nathanw 	bclr	#vHeadSel,%a1@(vBufA)
   1326       1.1   scottr 
   1327       1.1   scottr se03:
   1328  1.2.26.1  nathanw 	btst	#2,%d0			| bit 2 set => CA0 on
   1329       1.1   scottr 	bne	se04
   1330  1.2.26.1  nathanw 	tstb	%a0@(ph0L)
   1331       1.1   scottr 
   1332       1.1   scottr se04:
   1333  1.2.26.1  nathanw 	btst	#3,%d0			| bit 3 set => CA1 on
   1334       1.1   scottr 	bne	se05
   1335  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%d0	register selector
   1346  1.2.26.1  nathanw  *		%a0	IWM base address
   1347  1.2.26.1  nathanw  * Returns:	%d0	status
   1348       1.1   scottr  */
   1349       1.1   scottr dstatus:
   1350  1.2.26.1  nathanw 	tstb	%a0@(q6H)
   1351  1.2.26.1  nathanw 	moveb	%a0@(q7L),%d0
   1352  1.2.26.1  nathanw 	tstb	%a0@(q6L)		| leave in "read data reg"
   1353  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%a0	IWMBase
   1361  1.2.26.1  nathanw  *		%a1	VIABase
   1362  1.2.26.1  nathanw  *		%d0	register selector
   1363  1.2.26.1  nathanw  * Returns:	%d0	status (Bit 7)
   1364       1.1   scottr  */
   1365       1.1   scottr driveStat:
   1366  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%a0	IWMBase
   1377  1.2.26.1  nathanw  *		%a1	VIABase
   1378       1.1   scottr  * Returns:	-
   1379       1.1   scottr  */
   1380       1.1   scottr dtrigger:
   1381  1.2.26.1  nathanw 	tstb	%a0@(ph3H)		| LSTRB high
   1382  1.2.26.1  nathanw 	moveb	%a1@(vBufA),%a1@(vBufA)	| intelligent nop seen in q700 ROM
   1383  1.2.26.1  nathanw 	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.2.26.1  nathanw  * Parameters:	%a0	IWMBase
   1391  1.2.26.1  nathanw  *		%a1	VIABase
   1392  1.2.26.1  nathanw  *		%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.2.26.1  nathanw  * Parameters:	%a4	sectorHdr_t address
   1407  1.2.26.1  nathanw  * Returns:	%d0	result code
   1408  1.2.26.1  nathanw  * Uses:	%d0-%d4, %a0, %a2-%a4
   1409       1.1   scottr  */
   1410       1.1   scottr readSectHdr:
   1411  1.2.26.1  nathanw 	moveq	#3,%d4			| Read 3 chars from IWM for sync
   1412  1.2.26.2  nathanw 	movew	#1800,%d3		| Retries to sync to disk
   1413  1.2.26.1  nathanw 	moveq	#0,%d2			| Clear scratch regs
   1414  1.2.26.1  nathanw 	moveq	#0,%d1
   1415  1.2.26.1  nathanw 	moveq	#0,%d0
   1416  1.2.26.1  nathanw  	movel	_C_LABEL(IWMBase),%a0	| IWM base address
   1417       1.1   scottr 
   1418  1.2.26.1  nathanw 	tstb	%a0@(q7L)
   1419  1.2.26.1  nathanw 	lea	%a0@(q6L),%a0		| IWM data register
   1420       1.1   scottr shReadSy:
   1421  1.2.26.1  nathanw 	moveb	%a0@,%d2		| Read char
   1422  1.2.26.1  nathanw 	dbra	%d3,shSeekSync
   1423       1.1   scottr 
   1424  1.2.26.1  nathanw 	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.2.26.1  nathanw 	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.2.26.1  nathanw 	movew	#1500,%d3		| Retries to seek header
   1437       1.1   scottr shLeadIn:
   1438  1.2.26.1  nathanw 	lea	hdrLeadIn,%a3		| Sector header lead-in bytes
   1439  1.2.26.1  nathanw 	moveq	#0x03,%d4		| is 3 bytes long
   1440       1.1   scottr shLI1:
   1441  1.2.26.1  nathanw 	moveb	%a0@,%d2		| Get next byte
   1442       1.2   scottr 	bpl	shLI1			| No char at IWM, repeat read
   1443  1.2.26.1  nathanw 	dbra	%d3,shLI2
   1444  1.2.26.1  nathanw 	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.2.26.1  nathanw 	cmpb	%a3@+,%d2
   1449       1.1   scottr 	bne	shLeadIn		| If ne restart scan
   1450  1.2.26.1  nathanw 	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.2.26.1  nathanw 	 * Reg %d4 holds the checksum.
   1455       1.1   scottr 	 */
   1456  1.2.26.1  nathanw 	lea	diskTo-0x90,%a2		| Translate disk bytes -> 6&2
   1457       1.1   scottr shHdr1:
   1458  1.2.26.1  nathanw 	moveb	%a0@,%d0		| Get 1st char
   1459       1.1   scottr 	bpl	shHdr1
   1460  1.2.26.1  nathanw 	moveb	%a2@(0,%d0),%d1		| and remap it
   1461  1.2.26.1  nathanw 	moveb	%d1,%d4
   1462  1.2.26.1  nathanw 	rorw	#6,%d1			| separate 2:6, drop hi bits
   1463       1.1   scottr shHdr2:
   1464  1.2.26.1  nathanw 	moveb	%a0@,%d0		| Get 2nd char
   1465       1.1   scottr 	bpl	shHdr2
   1466  1.2.26.1  nathanw 	moveb	%a2@(0,%d0),%d2		| and remap it
   1467  1.2.26.1  nathanw 	eorb	%d2,%d4
   1468       1.1   scottr shHdr3:
   1469  1.2.26.1  nathanw 	moveb	%a0@,%d0		| Get 3rd char
   1470       1.1   scottr 	bpl	shHdr3
   1471  1.2.26.1  nathanw 	moveb	%a2@(0,%d0),%d1		| and remap it
   1472  1.2.26.1  nathanw 	eorb	%d1,%d4
   1473  1.2.26.1  nathanw 	rolw	#6,%d1			|
   1474       1.1   scottr shHdr4:
   1475  1.2.26.1  nathanw 	moveb	%a0@,%d0		| Get 4th char
   1476       1.1   scottr 	bpl	shHdr4
   1477  1.2.26.1  nathanw 	moveb	%a2@(0,%d0),%d3		| and remap it
   1478  1.2.26.1  nathanw 	eorb	%d3,%d4
   1479       1.1   scottr shHdr5:
   1480  1.2.26.1  nathanw 	moveb	%a0@,%d0		| Get checksum byte
   1481       1.1   scottr 	bpl	shHdr5
   1482  1.2.26.1  nathanw 	moveb	%a2@(0,%d0),%d5		| and remap it
   1483  1.2.26.1  nathanw 	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.2.26.1  nathanw 	 * %d1/lsb	track number
   1488  1.2.26.1  nathanw 	 * %d1/msb	bit 3 is side bit
   1489  1.2.26.1  nathanw 	 * %d2		sector number
   1490  1.2.26.1  nathanw 	 * %d3		???
   1491  1.2.26.1  nathanw 	 * %d5		checksum (=0)
   1492       1.1   scottr 	 *
   1493       1.1   scottr 	 * Next check for lead-out.
   1494       1.1   scottr 	 */
   1495  1.2.26.1  nathanw 	moveq	#1,%d4			| is 2 bytes long
   1496       1.1   scottr shHdr6:
   1497  1.2.26.1  nathanw 	moveb	%a0@,%d0		| Get token
   1498       1.1   scottr 	bpl	shHdr6
   1499  1.2.26.1  nathanw 	cmpb	%a3@+,%d0		| Check
   1500       1.1   scottr 	bne	shLOErr			| Fault!
   1501  1.2.26.1  nathanw 	dbra	%d4,shHdr6
   1502  1.2.26.1  nathanw 	movew	%d1,%d0			| Isolate side bit
   1503  1.2.26.1  nathanw 	lsrw	#8,%d0
   1504  1.2.26.1  nathanw 	moveb	%d0,%a4@+		| and store it
   1505  1.2.26.1  nathanw 	moveb	%d1,%a4@+		| Store track number
   1506  1.2.26.1  nathanw 	moveb	%d2,%a4@+		| and sector number
   1507  1.2.26.1  nathanw 	moveq	#0,%d0			| All is well
   1508       1.1   scottr 	bra	shDone
   1509       1.1   scottr 
   1510       1.1   scottr shCsErr:
   1511  1.2.26.1  nathanw 	moveq	#badCkSmErr,%d0		| Bad sector header checksum
   1512       1.1   scottr 	bra	shDone
   1513       1.1   scottr shLOErr:
   1514  1.2.26.1  nathanw 	moveq	#badBtSlpErr,%d0	| Bad address mark (no lead-out)
   1515       1.1   scottr 
   1516       1.1   scottr shDone:
   1517  1.2.26.1  nathanw 	tstl	%d0			| Set flags
   1518       1.1   scottr 	rts
   1519