Home | History | Annotate | Line # | Download | only in obio
iwm.s revision 1.1.2.1
      1  1.1.2.1  scottr /*	$NetBSD: iwm.s,v 1.1.2.1 1999/05/16 22:38:13 scottr Exp $	*/
      2      1.1  scottr 
      3      1.1  scottr /*
      4  1.1.2.1  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.1.2.1  scottr  * o  We run at spl4 to give the NMI switch a chance. All currently
     50  1.1.2.1  scottr  *    supported machines have no interrupt sources > 4 (SSC) -- the
     51  1.1.2.1  scottr  *    Q700 interrupt levels can be shifted around in A/UX mode,
     52  1.1.2.1  scottr  *    but we're not there, yet.
     53  1.1.2.1  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.1.2.1  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.1  scottr 	.extern	_TimeDBRA		| in mac68k/macrom.c
     77  1.1.2.1  scottr 	.extern _VIA1Base		| in mac68k/machdep.c
     78  1.1.2.1  scottr 	.extern	_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.1  scottr  *	a0	IWM base address
    149      1.1  scottr  *	a1	VIA1 base address
    150      1.1  scottr  *
    151      1.1  scottr  *	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.1  scottr  * Returns:	d0		flag
    170      1.1  scottr  */
    171      1.1  scottr ENTRY(iwmQueryDrvFlag)
    172      1.1  scottr 	link	a6,#0
    173      1.1  scottr 	moveml	d1/a0-a1,sp@-
    174      1.1  scottr 	movel	_IWMBase,a0
    175      1.1  scottr 	movel	_Via1Base,a1
    176      1.1  scottr 
    177      1.1  scottr 	movel	a6@(8),d0		| Get drive #
    178      1.1  scottr 	beq	quDrv00
    179      1.1  scottr 	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.1  scottr 	tstb	a0@(intDrive)		| SELECT; choose drive #0
    186      1.1  scottr 	bra	queryDrv
    187      1.1  scottr 
    188      1.1  scottr quDrv01:
    189      1.1  scottr 	tstb	a0@(extDrive)		| SELECT; choose drive #1
    190      1.1  scottr 
    191      1.1  scottr queryDrv:
    192      1.1  scottr 	movel	a6@(12),d0		| Get register #
    193      1.1  scottr 	bsr	driveStat
    194      1.1  scottr 
    195      1.1  scottr quDone:
    196      1.1  scottr 	moveml	sp@+,d1/a0-a1
    197      1.1  scottr 	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.1  scottr  * Returns:	d0		result code
    209      1.1  scottr  */
    210      1.1  scottr ENTRY(iwmReadSectHdr)
    211      1.1  scottr 	link	a6,#0
    212      1.1  scottr 	moveml	d1-d5/a0-a4,sp@-
    213      1.1  scottr 	movel	a6@(0x08),a4		| Get param block address
    214      1.1  scottr 	bsr	readSectHdr
    215      1.1  scottr 	moveml	sp@+,d1-d5/a0-a4
    216      1.1  scottr 	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.1  scottr  * Returns:	d0		result code
    230      1.1  scottr  */
    231      1.1  scottr ENTRY(iwmInit)
    232      1.1  scottr 	link	a6,#0
    233      1.1  scottr 	moveml	d2/a0,sp@-
    234      1.1  scottr 	movel	_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.1  scottr 	tstb	a0@(ph0L)		| CA0
    240      1.1  scottr 	tstb	a0@(ph1L)		| CA1
    241      1.1  scottr 	tstb	a0@(ph2L)		| CA2
    242      1.1  scottr 	tstb	a0@(ph3L)		| LSTRB
    243      1.1  scottr 
    244      1.1  scottr 	tstb	a0@(mtrOff)		| ENABLE; make sure drive is off
    245      1.1  scottr 	tstb	a0@(intDrive)		| SELECT; choose drive 1
    246      1.1  scottr 	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.1  scottr 	tstb	a0@(q6H)
    252      1.1  scottr 	andb	a0@(q7L),d0		| status register
    253      1.1  scottr 	tstb	a0@(q6L)
    254  1.1.2.1  scottr 	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.1  scottr 	movel	#0x00080000,d2		| ca. 500,000 retries = 1.5 sec
    262      1.1  scottr initLp:
    263      1.1  scottr 	moveq	#initIWMErr,d0		| Initialization error
    264      1.1  scottr 	subql	#1,d2
    265      1.1  scottr 	bmi	initErr
    266      1.1  scottr 	tstb	a0@(mtrOff)		| disable drive
    267      1.1  scottr 	tstb	a0@(q6H)
    268      1.1  scottr 	moveq	#0x3F,d0
    269      1.1  scottr 	andb	a0@(q7L),d0
    270      1.1  scottr 	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.1.2.1  scottr 	cmpib	#iwmMode,d0
    274      1.1  scottr 	beq	initDone
    275  1.1.2.1  scottr 	moveb	#iwmMode,a0@(q7H)	| Init IWM
    276      1.1  scottr 	tstb	a0@(q7L)
    277      1.1  scottr 	bra	initLp
    278      1.1  scottr 
    279      1.1  scottr initDone:
    280      1.1  scottr 	tstb	a0@(q6L)		| Prepare IWM for data
    281      1.1  scottr 	moveq	#0,d0			| noErr
    282      1.1  scottr 
    283      1.1  scottr initErr:
    284      1.1  scottr 	moveml	sp@+,d2/a0
    285      1.1  scottr 	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.1  scottr  * 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.1  scottr 	link	a6,#0
    303      1.1  scottr 	moveml	d1/a0-a1,sp@-
    304      1.1  scottr 	movel	_IWMBase,a0
    305      1.1  scottr 	movel	_Via1Base,a1
    306      1.1  scottr 
    307      1.1  scottr 	moveq	#-1,d1			| no drive
    308      1.1  scottr 
    309      1.1  scottr 	movel	a6@(0x08),d0		| check drive #
    310      1.1  scottr 	beq	chkDrv00
    311      1.1  scottr 	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.1  scottr 	tstb	a0@(intDrive)		| SELECT; choose drive #0
    318      1.1  scottr 	bra	chkDrive
    319      1.1  scottr 
    320      1.1  scottr chkDrv01:
    321      1.1  scottr 	tstb	a0@(extDrive)		| SELECT; choose drive #1
    322      1.1  scottr 
    323      1.1  scottr chkDrive:
    324      1.1  scottr 	moveq	#-2,d1			| error code
    325      1.1  scottr 	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.1  scottr 	moveq	#0,d1			| Drive found
    330      1.1  scottr 	tstb	a0@(mtrOn)		| ENABLE; activate drive
    331      1.1  scottr 	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.1  scottr 	bset	#0,d1			| 1 = no.
    342      1.1  scottr chkHasDisk:
    343      1.1  scottr 	moveq	#diskInserted,d0	| Disk inserted?
    344      1.1  scottr 	bsr	driveStat
    345      1.1  scottr 	bpl	chkMotorOn
    346      1.1  scottr 	bset	#1,d1			| 1 = No.
    347      1.1  scottr 	bra	chkDone
    348      1.1  scottr chkMotorOn:
    349      1.1  scottr 	moveq	#drvMotorState,d0	| Motor is running?
    350      1.1  scottr 	bsr	driveStat
    351      1.1  scottr 	bpl	chkWrtProt
    352      1.1  scottr 	bset	#2,d1			| 1 = No.
    353      1.1  scottr chkWrtProt:
    354      1.1  scottr 	moveq	#writeProtected,d0	| Disk is write protected?
    355      1.1  scottr 	bsr	driveStat
    356      1.1  scottr 	bpl	chkDD_HD
    357      1.1  scottr 	bset	#3,d1			| 1 = No.
    358      1.1  scottr chkDD_HD:
    359      1.1  scottr 	moveq	#diskIsHD,d0		| Disk is HD? (was "drive installed")
    360      1.1  scottr 	bsr	driveStat
    361      1.1  scottr 	bpl	chkDone
    362      1.1  scottr 	bset	#4,d1			| 1 = No.
    363      1.1  scottr chkDone:
    364      1.1  scottr 	movel	d1,d0
    365      1.1  scottr 	moveml	sp@+,d1/a0-a1
    366      1.1  scottr 	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.1  scottr  *		a0		IWMBase
    378      1.1  scottr  *		a1		VIABase
    379      1.1  scottr  * Returns:	d0		result code
    380      1.1  scottr  */
    381      1.1  scottr ENTRY(iwmDiskEject)
    382      1.1  scottr 	link	a6,#0
    383      1.1  scottr 	movel	_IWMBase,a0
    384      1.1  scottr 	movel	_Via1Base,a1
    385      1.1  scottr 
    386      1.1  scottr 	movel	a6@(0x08),d0		| Get drive #
    387      1.1  scottr 	beq	ejDrv00
    388      1.1  scottr 	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.1  scottr 	tstb	a0@(intDrive)		| SELECT; choose drive #0
    395      1.1  scottr 	bra	ejDisk
    396      1.1  scottr 
    397      1.1  scottr ejDrv01:
    398      1.1  scottr 	tstb	a0@(extDrive)		| SELECT; choose drive #1
    399      1.1  scottr ejDisk:
    400      1.1  scottr 	tstb	a0@(mtrOn)		| ENABLE; activate drive
    401      1.1  scottr 
    402      1.1  scottr 	moveq	#motorOffCmd,d0		| Motor off
    403      1.1  scottr  	bsr	driveCmd
    404      1.1  scottr 
    405      1.1  scottr 	moveq	#diskInserted,d0	| Disk inserted?
    406      1.1  scottr 	bsr	driveStat
    407      1.1  scottr 	bmi	ejDone
    408      1.1  scottr 
    409      1.1  scottr 	moveq	#ejectDiskCmd,d0	| Eject it
    410      1.1  scottr 	bsr	selDriveReg
    411      1.1  scottr 
    412      1.1  scottr 	tstb	a0@(ph3H)		| LSTRB high
    413      1.1  scottr #if USE_DELAY
    414      1.1  scottr 	movel	#1000,sp@-		| delay 1 ms
    415      1.1  scottr 	jsr	_C_LABEL(delay)
    416      1.1  scottr 	addqw	#4,sp			| clean up stack
    417      1.1  scottr #else
    418      1.1  scottr 	movew	#1,d0
    419      1.1  scottr 	bsr	iwmDelay
    420      1.1  scottr #endif
    421      1.1  scottr 	tstb	a0@(ph3L)		| LSTRB low
    422      1.1  scottr 	moveq	#0,d0			| All's well...
    423      1.1  scottr ejDone:
    424      1.1  scottr 	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.1  scottr  * Returns:	d0		drive #
    433      1.1  scottr  */
    434      1.1  scottr ENTRY(iwmSelectDrive)
    435      1.1  scottr 	link	a6,#0
    436      1.1  scottr 	moveml	a0-a1,sp@-
    437      1.1  scottr 	movel	_IWMBase,a0
    438      1.1  scottr 	movel	_Via1Base,a1
    439      1.1  scottr 
    440      1.1  scottr 	movel	a6@(8),d0		| Get drive #
    441      1.1  scottr 	bne	extDrv
    442      1.1  scottr 	tstb	a0@(intDrive)
    443      1.1  scottr 	bra	sdDone
    444      1.1  scottr extDrv:
    445      1.1  scottr 	tstb	a0@(extDrive)
    446      1.1  scottr sdDone:
    447      1.1  scottr 	moveml	sp@+,a0-a1
    448      1.1  scottr 	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.1  scottr  * Returns:	d0		motor cmd
    458      1.1  scottr  */
    459      1.1  scottr ENTRY(iwmMotor)
    460      1.1  scottr 	link	a6,#0
    461      1.1  scottr 	moveml	a0-a1,sp@-
    462      1.1  scottr 	movel	_IWMBase,a0
    463      1.1  scottr 	movel	_Via1Base,a1
    464      1.1  scottr 
    465      1.1  scottr 	movel	a6@(8),d0		| Get drive #
    466      1.1  scottr 	bne	mtDrv1
    467      1.1  scottr 	tstb	a0@(intDrive)
    468      1.1  scottr 	bra	mtSwitch
    469      1.1  scottr mtDrv1:
    470      1.1  scottr 	tstb	a0@(extDrive)
    471      1.1  scottr mtSwitch:
    472      1.1  scottr 	movel	#motorOnCmd,d0		| Motor ON
    473      1.1  scottr 	tstl	a6@(12)
    474      1.1  scottr 	bne	mtON
    475      1.1  scottr 	movel	#motorOffCmd,d0
    476      1.1  scottr mtON:
    477      1.1  scottr 	bsr	driveCmd
    478      1.1  scottr 
    479      1.1  scottr 	moveml	sp@+,a0-a1
    480      1.1  scottr 	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.1  scottr 	link	a6,#0
    494      1.1  scottr 	moveml	d1/a0-a1,sp@-
    495      1.1  scottr 	movel	_IWMBase,a0
    496      1.1  scottr 	movel	_Via1Base,a1
    497      1.1  scottr 
    498      1.1  scottr 	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.1  scottr 	moveq	#rdDataFrom0,d0		| Lower head
    505      1.1  scottr 	movel	a6@(0x08),d1		| Get side #
    506      1.1  scottr 	beq	ssSide0
    507      1.1  scottr 	moveq	#rdDataFrom1,d0		| Upper head
    508      1.1  scottr ssSide0:
    509      1.1  scottr 	bsr	driveStat
    510      1.1  scottr 
    511      1.1  scottr 	moveml	sp@+,d1/a0-a1
    512      1.1  scottr 	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.1  scottr  * Returns:	d0		result code
    523      1.1  scottr  */
    524      1.1  scottr ENTRY(iwmTrack00)
    525      1.1  scottr 	link	a6,#0
    526      1.1  scottr 	moveml	d1-d4/a0-a1,sp@-
    527      1.1  scottr 	movel	_IWMBase,a0
    528      1.1  scottr 	movel	_Via1Base,a1
    529      1.1  scottr 
    530      1.1  scottr 	moveq	#motorOnCmd,d0		| Switch drive motor on
    531      1.1  scottr 	bsr	driveCmd
    532      1.1  scottr 
    533      1.1  scottr 	moveq	#stepOutCmd,d0		| Step out
    534      1.1  scottr 	bsr	driveCmd
    535      1.1  scottr 
    536      1.1  scottr 	movew	#100,d2			| Max. tries
    537      1.1  scottr t0Retry:
    538      1.1  scottr 	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.1  scottr 	moveq	#doStepCmd,d0		| otherwise step
    543      1.1  scottr 	bsr	driveCmd
    544      1.1  scottr 	movew	#80,d4			| Retries
    545      1.1  scottr t0Still:
    546      1.1  scottr 	moveq	#stillStepping,d0	| Drive is still stepping?
    547      1.1  scottr 	bsr	driveStat
    548      1.1  scottr 	dbmi	d4,t0Still
    549      1.1  scottr 
    550      1.1  scottr 	cmpiw	#-1,d4
    551      1.1  scottr 	bne	t002
    552      1.1  scottr 
    553      1.1  scottr 	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.1  scottr 	movel	#15000,sp@-
    559      1.1  scottr 	jsr	_C_LABEL(delay)		| in mac68k/clock.c
    560      1.1  scottr 	addqw	#4,sp
    561      1.1  scottr #else
    562      1.1  scottr 	movew	#15,d0
    563      1.1  scottr 	bsr	iwmDelay
    564      1.1  scottr #endif
    565      1.1  scottr 
    566      1.1  scottr 	dbra	d2,t0Retry
    567      1.1  scottr 
    568      1.1  scottr 	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.1  scottr 	moveq	#0,d0
    573      1.1  scottr t0Done:
    574      1.1  scottr 	moveml	sp@+,d1-d4/a0-a1
    575      1.1  scottr 	unlk	a6
    576      1.1  scottr 	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.1  scottr  * returns:	d0		result code
    584      1.1  scottr  */
    585      1.1  scottr ENTRY(iwmSeek)
    586      1.1  scottr 	link	a6,#0
    587      1.1  scottr 	moveml	d1-d4/a0-a1,sp@-
    588      1.1  scottr 	movel	_IWMBase,a0
    589      1.1  scottr 	movel	_Via1Base,a1
    590      1.1  scottr 
    591      1.1  scottr 	moveq	#motorOnCmd,d0		| Switch drive motor on
    592      1.1  scottr 	bsr	driveCmd
    593      1.1  scottr 
    594      1.1  scottr 	moveq	#stepInCmd,d0		| Set step IN
    595      1.1  scottr 	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.1  scottr 	moveq	#stepOutCmd,d0		| Set step OUT
    600      1.1  scottr 	negl	d2			| Make # of steps positive
    601      1.1  scottr stepOut:
    602      1.1  scottr 	subql	#1,d2			| Loop exits for -1
    603      1.1  scottr 	bsr	driveCmd		| Set direction
    604      1.1  scottr stLoop:
    605      1.1  scottr 	moveq	#doStepCmd,d0
    606      1.1  scottr 	bsr	driveCmd		| Step one!
    607      1.1  scottr 	movew	#80,d4			| Retries
    608      1.1  scottr st01:
    609      1.1  scottr 	moveq	#stillStepping, d0	| Drive is still stepping?
    610      1.1  scottr 	bsr	driveStat
    611      1.1  scottr 	dbmi	d4,st01
    612      1.1  scottr 
    613      1.1  scottr 	cmpiw	#-1,d4
    614      1.1  scottr 	bne	st02
    615      1.1  scottr 
    616      1.1  scottr 	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.1  scottr 	movel	#30,sp@-
    622      1.1  scottr 	jsr	_C_LABEL(delay)		| in mac68k/clock.c
    623      1.1  scottr 	addqw	#4,sp
    624      1.1  scottr #else
    625      1.1  scottr 	movew	_TimeDBRA,d4		| dbra loops per ms
    626      1.1  scottr 	lsrw	#5,d4			| DIV 32
    627      1.1  scottr st03:	dbra	d4,st03			| makes ca. 30 us
    628      1.1  scottr #endif
    629      1.1  scottr 
    630      1.1  scottr 	dbra	d2,stLoop
    631      1.1  scottr 
    632      1.1  scottr 	moveq	#0,d2			| All is well
    633      1.1  scottr stDone:
    634      1.1  scottr 	movel	d2,d0
    635      1.1  scottr 	moveml	sp@+,d1-d4/a0-a1
    636      1.1  scottr 	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.1.2.1  scottr  *		XXX make "sizeof cylCache_t" a symbolic constant
    648  1.1.2.1  scottr  *
    649      1.1  scottr  * Parameters:	fp+08	l	Address of sector data buffer (512 bytes)
    650      1.1  scottr  *		fp+12	l	Address of sector header struct (I/O)
    651  1.1.2.1  scottr  *		fp+16	l	Address of cache buffer ptr array
    652      1.1  scottr  * Returns:	d0		result code
    653      1.1  scottr  * Local:	fp-2	w	CPU status register
    654      1.1  scottr  *		fp-3	b	side,
    655      1.1  scottr  *		fp-4	b	track,
    656      1.1  scottr  *		fp-5	b	sector wanted
    657  1.1.2.1  scottr  *		fp-6	b	retry count
    658  1.1.2.1  scottr  *		fp-7	b	sector read
    659      1.1  scottr  */
    660      1.1  scottr ENTRY(iwmReadSector)
    661  1.1.2.1  scottr 	link	a6,#-8
    662      1.1  scottr 	moveml	d1-d7/a0-a5,sp@-
    663      1.1  scottr 
    664  1.1.2.1  scottr  	movel	_Via1Base,a1
    665  1.1.2.1  scottr 	movel	a6@(o_hdr),a4		| Addr of sector header struct
    666      1.1  scottr 
    667  1.1.2.1  scottr 	moveb	a4@+,a6@(-3)		| Save side bit,
    668  1.1.2.1  scottr 	moveb	a4@+,a6@(-4)		| track#,
    669  1.1.2.1  scottr 	moveb	a4@,a6@(-5)		| sector#
    670  1.1.2.1  scottr 	moveb	#2*maxGCRSectors,a6@(-6) | Max. retry count
    671      1.1  scottr 
    672      1.1  scottr 	movew	sr,a6@(-2)		| Save CPU status register
    673  1.1.2.1  scottr 	oriw	#0x0600,sr		| Block all interrupts
    674      1.1  scottr 
    675  1.1.2.1  scottr rsNextSect:
    676  1.1.2.1  scottr 	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.1.2.1  scottr 	movel	a6@(o_hdr),a4		| Sector header struct
    684      1.1  scottr 
    685  1.1.2.1  scottr 	moveb	a4@(o_side),d1		| Get actual side
    686      1.1  scottr 	lsrb	#3,d1			| "Normalize" side bit (to bit 0)
    687      1.1  scottr 	andb	#1,d1
    688      1.1  scottr 	moveb	a6@(-3),d2		| Get wanted side
    689      1.1  scottr 	eorb	d1,d2			| Compare side bits
    690      1.1  scottr 	bne	rsSeekErr		| Should be equal!
    691      1.1  scottr 
    692  1.1.2.1  scottr 	moveb	a6@(-4),d1		| Get track# we want
    693  1.1.2.1  scottr 	cmpb	a4@(o_track),d1		| Compare to the header we've read
    694      1.1  scottr 	beq	rsGetSect
    695  1.1.2.1  scottr 
    696      1.1  scottr rsSeekErr:
    697      1.1  scottr 	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.1.2.1  scottr 	 *	a0 points to data register of IWM as set up by readSectHdr
    704  1.1.2.1  scottr 	 *	a2 points to 'diskTo' translation table
    705      1.1  scottr 	 *	a4 points to tags buffer
    706      1.1  scottr 	 */
    707      1.1  scottr rsGetSect:
    708  1.1.2.1  scottr 	moveb	a4@(2),a6@(-7)		| save sector number
    709      1.1  scottr 	lea	a4@(3),a4		| Beginning of tag buffer
    710  1.1.2.1  scottr 	moveq	#50,d3			| Max. retries for sector lookup
    711      1.1  scottr rsLeadIn:
    712      1.1  scottr 	lea	dataLeadIn,a3		| Sector data lead-in
    713      1.1  scottr 	moveq	#0x03,d4		| is 3 bytes long
    714      1.1  scottr rsLI1:
    715      1.1  scottr 	moveb	a0@,d2			| Get next byte
    716      1.1  scottr 	bpl	rsLI1
    717      1.1  scottr 	dbra	d3,rsLI2
    718      1.1  scottr 	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.1  scottr 	cmpb	a3@+,d2
    723      1.1  scottr 	bne	rsLeadIn		| If ne restart scan
    724      1.1  scottr 	subqw	#1,d4
    725      1.1  scottr 	bne	rsLI1
    726  1.1.2.1  scottr 
    727      1.1  scottr 	/*
    728      1.1  scottr 	 * We have found the lead-in. Now get the 12 tag bytes.
    729      1.1  scottr 	 * (We leave a3 pointing to 'dataLeadOut' for later.)
    730      1.1  scottr 	 */
    731      1.1  scottr rsTagNyb0:
    732      1.1  scottr 	moveb	a0@,d3			| Get a char,
    733      1.1  scottr 	bpl	rsTagNyb0
    734      1.1  scottr 	moveb	a2@(0,d3),a4@+		| remap and store it
    735      1.1  scottr 
    736      1.1  scottr 	moveq	#0,d5			| Clear checksum registers
    737      1.1  scottr 	moveq	#0,d6
    738      1.1  scottr 	moveq	#0,d7
    739      1.1  scottr 	moveq	#10,d4			| Loop counter
    740      1.1  scottr 	moveq	#0,d3			| Data scratch reg
    741      1.1  scottr 
    742      1.1  scottr rsTags:
    743      1.1  scottr rsTagNyb1:
    744      1.1  scottr 	moveb	a0@,d3			| Get 2 bit nibbles
    745      1.1  scottr 	bpl	rsTagNyb1
    746      1.1  scottr 	moveb	a2@(0,d3),d1		| Remap disk byte
    747      1.1  scottr 	rolb	#2,d1
    748      1.1  scottr 	moveb	d1,d2
    749      1.1  scottr 	andib	#0xC0,d2		| Get top 2 bits for first byte
    750      1.1  scottr rsTagNyb2:
    751      1.1  scottr 	moveb	a0@,d3			| Get first 6 bit nibble
    752      1.1  scottr 	bpl	rsTagNyb2
    753      1.1  scottr 	orb	a2@(0,d3),d2		| Remap it and complete first byte
    754      1.1  scottr 
    755      1.1  scottr 	moveb	d7,d3			| The X flag bit (a copy of the carry
    756      1.1  scottr 	addb	d7,d3			| flag) is added with the next addx
    757      1.1  scottr 
    758      1.1  scottr 	rolb	#1,d7
    759      1.1  scottr 	eorb	d7,d2
    760      1.1  scottr 	moveb	d2,a4@+			| Store tag byte
    761      1.1  scottr 	addxb	d2,d5			| See above
    762      1.1  scottr 
    763      1.1  scottr 	rolb	#2,d1
    764      1.1  scottr 	moveb	d1,d2
    765      1.1  scottr 	andib	#0xC0,d2		| Get top 2 bits for second byte
    766      1.1  scottr rsTagNyb3:
    767      1.1  scottr 	moveb	a0@,d3			| Get second 6 bit nibble
    768      1.1  scottr 	bpl	rsTagNyb3
    769      1.1  scottr 	orb	a2@(0,d3),d2		| remap it and complete byte
    770      1.1  scottr 	eorb	d5,d2
    771      1.1  scottr 	moveb	d2,a4@+			| Store tag byte
    772      1.1  scottr 	addxb	d2,d6
    773      1.1  scottr 
    774      1.1  scottr 	rolb	#2,d1
    775      1.1  scottr 	andib	#0xC0,d1		| Get top 2 bits for third byte
    776      1.1  scottr rsTagNyb4:
    777      1.1  scottr 	moveb	a0@,d3			| Get third 6 bit nibble
    778      1.1  scottr 	bpl	rsTagNyb4
    779      1.1  scottr 	orb	a2@(0,d3),d1		| remap it and complete byte
    780      1.1  scottr 	eorb	d6,d1
    781      1.1  scottr 	moveb	d1,a4@+			| Store tag byte
    782      1.1  scottr 	addxb	d1,d7
    783      1.1  scottr 
    784      1.1  scottr 	subqw	#3,d4			| Update byte counter (four 6&2 encoded
    785      1.1  scottr 	bpl	rsTags			| disk bytes make three data bytes).
    786  1.1.2.1  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.1.2.1  scottr 	 * Compare sector # to what we wanted: If it matches, read directly
    793  1.1.2.1  scottr 	 * to buffer, else read to track cache.
    794      1.1  scottr 	 */
    795      1.1  scottr 	movew	#0x01FE,d4		| Loop counter
    796  1.1.2.1  scottr 	moveq	#0,d1			| Clear d1.L
    797  1.1.2.1  scottr 	moveb	a6@(-7),d1		| Get sector# we have read
    798  1.1.2.1  scottr 	cmpb	a6@(-5),d1		| Compare to the sector# we want
    799  1.1.2.1  scottr 	bne	rsToCache
    800  1.1.2.1  scottr 	movel	a6@(o_buf),a4		| Sector data buffer
    801  1.1.2.1  scottr 	bra	rsData
    802  1.1.2.1  scottr rsToCache:
    803  1.1.2.1  scottr 	movel	a6@(o_rslots),a4	| Base address of slot array
    804  1.1.2.1  scottr 	lslw	#3,d1			| sizeof cylCacheSlot_t is 8 bytes
    805  1.1.2.1  scottr 	movel	#-1,a4@(o_valid,d1)
    806  1.1.2.1  scottr 	movel	a4@(o_secbuf,d1),a4	| and get its buffer ptr
    807      1.1  scottr rsData:
    808      1.1  scottr rsDatNyb1:
    809      1.1  scottr 	moveb	a0@,d3			| Get 2 bit nibbles
    810      1.1  scottr 	bpl	rsDatNyb1
    811      1.1  scottr 	moveb	a2@(0,d3),d1		| Remap disk byte
    812      1.1  scottr 	rolb	#2,d1
    813      1.1  scottr 	moveb	d1,d2
    814      1.1  scottr 	andib	#0xC0,d2		| Get top 2 bits for first byte
    815      1.1  scottr rsDatNyb2:
    816      1.1  scottr 	moveb	a0@,d3			| Get first 6 bit nibble
    817      1.1  scottr 	bpl	rsDatNyb2
    818      1.1  scottr 	orb	a2@(0,d3),d2		| Remap it and complete first byte
    819      1.1  scottr 
    820      1.1  scottr 	moveb	d7,d3			| The X flag bit (a copy of the carry
    821      1.1  scottr 	addb	d7,d3			| flag) is added with the next addx
    822      1.1  scottr 
    823      1.1  scottr 	rolb	#1,d7
    824      1.1  scottr 	eorb	d7,d2
    825      1.1  scottr 	moveb	d2,a4@+			| Store data byte
    826      1.1  scottr 	addxb	d2,d5			| See above
    827      1.1  scottr 
    828      1.1  scottr 	rolb	#2,d1
    829      1.1  scottr 	moveb	d1,d2
    830      1.1  scottr 	andib	#0xC0,d2		| Get top 2 bits for second byte
    831      1.1  scottr rsDatNyb3:
    832      1.1  scottr 	moveb	a0@,d3			| Get second 6 bit nibble
    833      1.1  scottr 	bpl	rsDatNyb3
    834      1.1  scottr 	orb	a2@(0,d3),d2		| Remap it and complete byte
    835      1.1  scottr 	eorb	d5,d2
    836      1.1  scottr 	moveb	d2,a4@+			| Store data byte
    837      1.1  scottr 	addxb	d2,d6
    838      1.1  scottr 	tstw	d4
    839      1.1  scottr 	beq	rsCkSum			| Data read, continue with checksums
    840      1.1  scottr 
    841      1.1  scottr 	rolb	#2,d1
    842      1.1  scottr 	andib	#0xC0,d1		| Get top 2 bits for third byte
    843      1.1  scottr rsDatNyb4:
    844      1.1  scottr 	moveb	a0@,d3			| Get third 6 bit nibble
    845      1.1  scottr 	bpl	rsDatNyb4
    846      1.1  scottr 	orb	a2@(0,d3),d1		| Remap it and complete byte
    847      1.1  scottr 	eorb	d6,d1
    848      1.1  scottr 	moveb	d1,a4@+			| Store data byte
    849      1.1  scottr 	addxb	d1,d7
    850      1.1  scottr 	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.1  scottr 	 * maintained in D5/D6/D7 for the 1st/2nd/3rd data byte of each group.
    857      1.1  scottr 	 */
    858      1.1  scottr rsCkSum:
    859      1.1  scottr rsCkS1:
    860      1.1  scottr 	moveb	a0@,d3			| Get 2 bit nibbles
    861      1.1  scottr 	bpl	rsCkS1
    862      1.1  scottr 	moveb	a2@(0,d3),d1		| Remap disk byte
    863      1.1  scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    864      1.1  scottr 	rolb	#2,d1
    865      1.1  scottr 	moveb	d1,d2
    866      1.1  scottr 	andib	#0xC0,d2		| Get top 2 bits for first byte
    867      1.1  scottr rsCkS2:
    868      1.1  scottr 	moveb	a0@,d3			| Get first 6 bit nibble
    869      1.1  scottr 	bpl	rsCkS2
    870      1.1  scottr 	moveb	a2@(0,d3),d3		| and remap it
    871      1.1  scottr 	bmi	rsBadCkSum		| Fault! ( > 0x3f is bad read)
    872      1.1  scottr 	orb	d3,d2			| Merge 6&2
    873      1.1  scottr 	cmpb	d2,d5			| Compare first checksum to D5
    874      1.1  scottr 	bne	rsBadCkSum		| Fault! (Checksum)
    875      1.1  scottr 
    876      1.1  scottr 	rolb	#2,d1
    877      1.1  scottr 	moveb	d1,d2
    878      1.1  scottr 	andib	#0xC0,d2		| Get top 2 bits for second byte
    879      1.1  scottr rsCkS3:
    880      1.1  scottr 	moveb	a0@,d3			| Get second 6 bit nibble
    881      1.1  scottr 	bpl	rsCkS3
    882      1.1  scottr 	moveb	a2@(0,d3),d3		| and remap it
    883      1.1  scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    884      1.1  scottr 	orb	d3,d2			| Merge 6&2
    885      1.1  scottr 	cmpb	d2,d6			| Compare second checksum to D6
    886      1.1  scottr 	bne	rsBadCkSum		| Fault! (Checksum)
    887      1.1  scottr 
    888      1.1  scottr 	rolb	#2,d1
    889      1.1  scottr 	andib	#0xC0,d1		| Get top 2 bits for second byte
    890      1.1  scottr rsCkS4:
    891      1.1  scottr 	moveb	a0@,d3			| Get third 6 bit nibble
    892      1.1  scottr 	bpl	rsCkS4
    893      1.1  scottr 	moveb	a2@(0,d3),d3		| and remap it
    894      1.1  scottr 	bmi	rsBadCkSum		| Fault! (Bad read)
    895      1.1  scottr 	orb	d3,d1			| Merge 6&2
    896      1.1  scottr 	cmpb	d1,d7			| Compare third checksum to D7
    897      1.1  scottr 	beq	rsLdOut			| Fault! (Checksum)
    898      1.1  scottr 
    899      1.1  scottr rsBadCkSum:
    900      1.1  scottr 	moveq	#badDCkSum,d0		| Bad data mark checksum
    901      1.1  scottr 	bra	rsDone
    902      1.1  scottr 
    903      1.1  scottr rsBadDBtSlp:
    904      1.1  scottr 	moveq	#badDBtSlp,d0		| One of the data mark bit slip
    905      1.1  scottr 	bra	rsDone			| nibbles was incorrect
    906      1.1  scottr 
    907      1.1  scottr 	/*
    908      1.1  scottr 	 * We have gotten the checksums allright, now look for the
    909      1.1  scottr 	 * sector data lead-out 'DE AA'
    910      1.1  scottr 	 * (We have a3 still pointing to 'dataLeadOut'; this part of the
    911      1.1  scottr 	 * table is used for writing to disk, too.)
    912      1.1  scottr 	 */
    913      1.1  scottr rsLdOut:
    914      1.1  scottr 	moveq	#1,d4			| Is two bytes long {1,0}
    915      1.1  scottr rsLdOut1:
    916      1.1  scottr 	moveb	a0@,d3			| Get token
    917      1.1  scottr 	bpl	rsLdOut1
    918      1.1  scottr 	cmpb	a3@+,d3
    919      1.1  scottr 	bne	rsBadDBtSlp		| Fault!
    920      1.1  scottr 	dbra	d4,rsLdOut1
    921      1.1  scottr 	moveq	#0,d0			| OK.
    922  1.1.2.1  scottr 
    923  1.1.2.1  scottr 	/*
    924  1.1.2.1  scottr 	 * See if we got the sector we wanted. If not, and no error
    925  1.1.2.1  scottr 	 * occurred, mark buffer valid. Else ignore the sector.
    926  1.1.2.1  scottr 	 * Then, read on.
    927  1.1.2.1  scottr 	 */
    928      1.1  scottr rsDone:
    929  1.1.2.1  scottr 	movel	a6@(o_hdr),a4		| Addr of sector header struct
    930  1.1.2.1  scottr 	moveb	a4@(o_sector),d1	| Get # of sector we have just read
    931  1.1.2.1  scottr 	cmpb	a6@(-5),d1		| Compare to the sector we want
    932  1.1.2.1  scottr 	beq	rsAllDone
    933  1.1.2.1  scottr 
    934  1.1.2.1  scottr 	tstb	d0			| Any error? Simply ignore data
    935  1.1.2.1  scottr 	beq	rsBufValid
    936  1.1.2.1  scottr 	lslw	#3,d1			| sizeof cylCacheSlot_t is 8 bytes
    937  1.1.2.1  scottr 	movel	a6@(o_rslots),a4
    938  1.1.2.1  scottr 	clrl	a4@(o_valid,d1)		| Mark buffer content "invalid"
    939  1.1.2.1  scottr 
    940  1.1.2.1  scottr rsBufValid:
    941  1.1.2.1  scottr 	subqb	#1,a6@(-6)		| max. retries
    942  1.1.2.1  scottr 	bne	rsNextSect
    943  1.1.2.1  scottr 					| Sector not found, but
    944  1.1.2.1  scottr 	tstb	d0			| don't set error code if we
    945  1.1.2.1  scottr 	bne	rsAllDone		| already have one.
    946  1.1.2.1  scottr 	moveq	#sectNFErr,d0
    947  1.1.2.1  scottr rsAllDone:
    948      1.1  scottr 	movew	a6@(-2),sr		| Restore interrupt mask
    949      1.1  scottr 	moveml	sp@+,d1-d7/a0-a5
    950      1.1  scottr 	unlk	a6
    951  1.1.2.1  scottr 	rts
    952      1.1  scottr 
    953      1.1  scottr 
    954      1.1  scottr /*
    955      1.1  scottr  * iwmWriteSector -- encode and write data to the specified sector.
    956      1.1  scottr  *
    957      1.1  scottr  * TODO:	Poll SCC as long as interrupts are disabled (see top comment)
    958      1.1  scottr  *		Understand and document the checksum algorithm!
    959      1.1  scottr  *
    960  1.1.2.1  scottr  *		XXX Use registers more efficiently
    961  1.1.2.1  scottr  *
    962  1.1.2.1  scottr  * Parameters:	fp+8	l	Address of sector header struct (I/O)
    963  1.1.2.1  scottr  *		fp+12	l	Address of cache buffer ptr array
    964      1.1  scottr  * Returns:	d0		result code
    965      1.1  scottr  *
    966      1.1  scottr  * Local:	fp-2	w	CPU status register
    967      1.1  scottr  *		fp-3	b	side,
    968      1.1  scottr  *		fp-4	b	track,
    969      1.1  scottr  *		fp-5	b	sector wanted
    970  1.1.2.1  scottr  *		fp-6	b	retry count
    971  1.1.2.1  scottr  *		fp-10	b	current slot
    972      1.1  scottr  */
    973      1.1  scottr ENTRY(iwmWriteSector)
    974  1.1.2.1  scottr 	link	a6,#-10
    975      1.1  scottr 	moveml	d1-d7/a0-a5,sp@-
    976      1.1  scottr 
    977  1.1.2.1  scottr  	movel	_Via1Base,a1
    978  1.1.2.1  scottr 	movel	a6@(o_hdr),a4		| Addr of sector header struct
    979      1.1  scottr 
    980  1.1.2.1  scottr 	moveb	a4@+,a6@(-3)		| Save side bit,
    981  1.1.2.1  scottr 	moveb	a4@+,a6@(-4)		| track#,
    982  1.1.2.1  scottr 	moveb	a4@,a6@(-5)		| sector#
    983  1.1.2.1  scottr 	moveb	#maxGCRSectors,a6@(-6)	| Max. retry count
    984      1.1  scottr 
    985      1.1  scottr 	movew	sr,a6@(-2)		| Save CPU status register
    986  1.1.2.1  scottr 	oriw	#0x0600,sr		| Block all interrupts
    987      1.1  scottr 
    988  1.1.2.1  scottr wsNextSect:
    989  1.1.2.1  scottr 	movel	a6@(o_hdr),a4
    990      1.1  scottr 	bsr	readSectHdr		| Get next available sector header
    991  1.1.2.1  scottr 	bne	wsAllDone		| Return if error
    992      1.1  scottr 
    993      1.1  scottr 	/*
    994      1.1  scottr 	 * Is this the right track & side? If not, return with error
    995      1.1  scottr 	 */
    996  1.1.2.1  scottr 	movel	a6@(o_hdr),a4		| Sector header struct
    997      1.1  scottr 
    998  1.1.2.1  scottr 	moveb	a4@(o_side),d1		| Get side#
    999      1.1  scottr 	lsrb	#3,d1			| "Normalize" side bit...
   1000      1.1  scottr 	andb	#1,d1
   1001      1.1  scottr 	moveb	a6@(-3),d2		| Get wanted side
   1002      1.1  scottr 	eorb	d1,d2			| Compare side bits
   1003      1.1  scottr 	bne	wsSeekErr
   1004      1.1  scottr 
   1005      1.1  scottr 	moveb	a6@(-4),d1		| Get wanted track#
   1006  1.1.2.1  scottr 	cmpb	a4@(o_track),d1		| Compare to the read header
   1007      1.1  scottr 	beq	wsCompSect
   1008      1.1  scottr 
   1009      1.1  scottr wsSeekErr:
   1010      1.1  scottr 	moveq	#seekErr,d0		| Wrong track or side
   1011  1.1.2.1  scottr 	bra	wsAllDone
   1012      1.1  scottr 
   1013      1.1  scottr 	/*
   1014  1.1.2.1  scottr 	 * Look up the current sector number in the cache.
   1015  1.1.2.1  scottr 	 * If the buffer is dirty ("valid"), write it to disk. If not,
   1016  1.1.2.1  scottr 	 * loop over all the slots and return if all of them are clean.
   1017  1.1.2.1  scottr 	 *
   1018  1.1.2.1  scottr 	 * Alternatively, we could decrement a "dirty sectors" counter here.
   1019      1.1  scottr 	 */
   1020      1.1  scottr wsCompSect:
   1021      1.1  scottr 	moveq	#0,d1			| Clear register
   1022  1.1.2.1  scottr 	moveb	a4@(o_sector),d1	| get the # of header read
   1023  1.1.2.1  scottr 	lslw	#3,d1			| sizeof cylCacheSlot_t is 8 bytes
   1024  1.1.2.1  scottr 	movel	a6@(o_wslots),a4
   1025  1.1.2.1  scottr 	tstl	a4@(o_valid,d1)		| Sector dirty?
   1026  1.1.2.1  scottr 	bne	wsBufDirty
   1027  1.1.2.1  scottr 
   1028  1.1.2.1  scottr 	moveq	#maxGCRSectors-1,d2	| Any dirty sectors left?
   1029  1.1.2.1  scottr wsChkDty:
   1030  1.1.2.1  scottr 	movew	d2,d1
   1031  1.1.2.1  scottr 	lslw	#3,d1			| sizeof cylCacheSlot_t is 8 bytes
   1032  1.1.2.1  scottr 	tstl	a4@(o_valid,d1)
   1033  1.1.2.1  scottr 	bne	wsNextSect		| Sector dirty?
   1034  1.1.2.1  scottr 	dbra	d2,wsChkDty
   1035      1.1  scottr 
   1036  1.1.2.1  scottr 	bra	wsAllDone		| We are through with this track.
   1037  1.1.2.1  scottr 
   1038  1.1.2.1  scottr 
   1039      1.1  scottr 	/*
   1040      1.1  scottr 	 * Write sync pattern and sector data lead-in 'D5 AA'. The
   1041      1.1  scottr 	 * missing 'AD' is made up by piping 0x0B through the nibble
   1042      1.1  scottr 	 * table (toDisk).
   1043      1.1  scottr 	 *
   1044      1.1  scottr 	 * To set up IWM for writing:
   1045      1.1  scottr 	 *
   1046      1.1  scottr 	 * access q6H & write first byte to q7H.
   1047      1.1  scottr 	 * Then check bit 7 of q6L (status reg) for 'IWM ready'
   1048      1.1  scottr 	 * and write subsequent bytes to q6H.
   1049      1.1  scottr 	 *
   1050      1.1  scottr 	 * Registers:
   1051  1.1.2.1  scottr 	 *	a0	IWM base address (later: data register)
   1052      1.1  scottr 	 *	a1	Via1Base
   1053      1.1  scottr 	 *	a2	IWM handshake register
   1054      1.1  scottr 	 *	a3	data (tags buffer, data buffer)
   1055  1.1.2.1  scottr 	 *	a4	Sync pattern, 'toDisk' translation table
   1056      1.1  scottr 	 */
   1057  1.1.2.1  scottr wsBufDirty:
   1058      1.1  scottr 	movel	_IWMBase,a0
   1059  1.1.2.1  scottr 	lea	a4@(0,d1),a3
   1060  1.1.2.1  scottr 	movel	a3,a6@(-10)		| Save ptr to current slot
   1061      1.1  scottr 	tstb	a0@(q6H)		| Enable writing to disk
   1062  1.1.2.1  scottr 	movel	a6@(o_hdr),a4		| Sector header struct
   1063  1.1.2.1  scottr 	lea	a4@(o_Tags),a3		| Point a3 to tags buffer
   1064      1.1  scottr 	lea	syncPattern,a4
   1065      1.1  scottr 
   1066      1.1  scottr 	moveb	a4@+,a0@(q7H)		| Write first sync byte
   1067      1.1  scottr 	lea	a0@(q6L),a2		| Point a2 to handshake register
   1068      1.1  scottr 	lea	a0@(q6H),a0		| Point a0 to IWM data register
   1069      1.1  scottr 
   1070      1.1  scottr 	moveq	#6,d0			| Loop counter for sync bytes
   1071      1.1  scottr 	moveq	#0,d2
   1072      1.1  scottr 	moveq	#0,d3
   1073      1.1  scottr 	movel	#0x02010009,d4		| Loop counters for tag/sector data
   1074      1.1  scottr 
   1075      1.1  scottr 	/*
   1076      1.1  scottr 	 * Write 5 sync bytes and first byte of sector data lead-in
   1077      1.1  scottr 	 */
   1078      1.1  scottr wsLeadIn:
   1079      1.1  scottr 	moveb	a4@+,d1			| Get next sync byte
   1080      1.1  scottr wsLI1:
   1081      1.1  scottr 	tstb	a2@			| IWM ready?
   1082      1.1  scottr 	bpl	wsLI1
   1083      1.1  scottr 	moveb	d1,a0@			| Write it to disk
   1084      1.1  scottr 	subqw	#1,d0
   1085      1.1  scottr 	bne	wsLeadIn
   1086      1.1  scottr 
   1087      1.1  scottr 	moveb	a4@+,d1			| Write 2nd byte of sector lead-in
   1088      1.1  scottr 	lea	toDisk,a4		| Point a4 to nibble translation table
   1089      1.1  scottr wsLI2:
   1090      1.1  scottr 	tstb	a2@			| IWM ready?
   1091      1.1  scottr 	bpl	wsLI2
   1092      1.1  scottr 	moveb	d1,a0@			| Write it to disk
   1093      1.1  scottr 
   1094      1.1  scottr 	moveq	#0,d5			| Clear checksum registers
   1095      1.1  scottr 	moveq	#0,d6
   1096      1.1  scottr 	moveq	#0,d7
   1097      1.1  scottr 
   1098      1.1  scottr 	moveq	#0x0B,d1		| 3rd byte of sector data lead-in
   1099      1.1  scottr 					| (Gets translated to 0xAD)
   1100      1.1  scottr 	moveb	a3@+,d2			| Get 1st byte from tags buffer
   1101      1.1  scottr 	bra	wsDataEntry
   1102      1.1  scottr 
   1103      1.1  scottr 	/*
   1104      1.1  scottr 	 * The following loop reads the content of the tags buffer (12 bytes)
   1105      1.1  scottr 	 * and the data buffer (512 bytes).
   1106      1.1  scottr 	 * Each pass reads out three bytes and
   1107      1.1  scottr 	 * a) splits them 6&2 into three 6 bit nibbles and a fourth byte
   1108      1.1  scottr 	 *    consisting of the three 2 bit nibbles
   1109      1.1  scottr 	 * b) encodes the nibbles with a table to disk bytes (bit 7 set, no
   1110      1.1  scottr 	 *    more than two consecutive zero bits) and writes them to disk as
   1111      1.1  scottr 	 *
   1112      1.1  scottr 	 *    00mmnnoo		fragment 2 bit nibbles
   1113      1.1  scottr 	 *    00mmmmmm		6 bit nibble -- first byte
   1114      1.1  scottr 	 *    00nnnnnn		6 bit nibble -- second byte
   1115      1.1  scottr 	 *    00oooooo		6 bit nibble -- third byte
   1116      1.1  scottr 	 *
   1117      1.1  scottr 	 * c) adds up three 8 bit checksums, one for each of the bytes written.
   1118      1.1  scottr 	 */
   1119  1.1.2.1  scottr wsSD1:
   1120  1.1.2.1  scottr 	movel	a6@(-10),a3		| Get ptr to current slot
   1121  1.1.2.1  scottr 	movel	a3@(o_secbuf),a3	| Get start of sector data buffer
   1122      1.1  scottr 
   1123      1.1  scottr wsData:
   1124      1.1  scottr 	addxb	d2,d7
   1125      1.1  scottr 	eorb	d6,d2
   1126      1.1  scottr 	moveb	d2,d3
   1127      1.1  scottr 	lsrw	#6,d3			| Put 2 bit nibbles into place
   1128      1.1  scottr wsRDY01:
   1129      1.1  scottr 	tstb	a2@			| IWM ready?
   1130      1.1  scottr 	bpl	wsRDY01
   1131      1.1  scottr 	moveb	a4@(0,d3),a0@		| Translate nibble and write
   1132      1.1  scottr 	subqw	#3,d4			| Update counter
   1133      1.1  scottr 	moveb	d7,d3
   1134      1.1  scottr 	addb	d7,d3			| Set X flag (??)
   1135      1.1  scottr 	rolb	#1,d7
   1136      1.1  scottr 	andib	#0x3F,d0
   1137      1.1  scottr wsRDY02:
   1138      1.1  scottr 	tstb	a2@			| IWM ready?
   1139      1.1  scottr 	bpl	wsRDY02
   1140      1.1  scottr 	moveb	a4@(0,d0),a0@		| Translate nibble and write
   1141      1.1  scottr 
   1142      1.1  scottr 	/*
   1143      1.1  scottr 	 * We enter with the last byte of the sector data lead-in
   1144      1.1  scottr 	 * between our teeth (D1, that is).
   1145      1.1  scottr 	 */
   1146      1.1  scottr wsDataEntry:
   1147      1.1  scottr 	moveb	a3@+,d0			| Get first byte
   1148      1.1  scottr 	addxb	d0,d5
   1149      1.1  scottr 	eorb	d7,d0
   1150      1.1  scottr 	moveb	d0,d3			| Keep top two bits
   1151      1.1  scottr 	rolw	#2,d3			| by shifting them to MSByte
   1152      1.1  scottr 	andib	#0x3F,d1
   1153      1.1  scottr wsRDY03:
   1154      1.1  scottr 	tstb	a2@			| IWM ready?
   1155      1.1  scottr 	bpl	wsRDY03
   1156      1.1  scottr 	moveb	a4@(0,d1),a0@		| Translate nibble and write
   1157      1.1  scottr 
   1158      1.1  scottr 	moveb	a3@+,d1			| Get second byte
   1159      1.1  scottr 	addxb	d1,d6
   1160      1.1  scottr 	eorb	d5,d1
   1161      1.1  scottr 	moveb	d1,d3			| Keep top two bits
   1162      1.1  scottr 	rolw	#2,d3			| by shifting them to MSByte
   1163      1.1  scottr 	andib	#0x3F,d2
   1164      1.1  scottr wsRDY04:
   1165      1.1  scottr 	tstb	a2@			| IWM ready?
   1166      1.1  scottr 	bpl	wsRDY04
   1167      1.1  scottr 	moveb	a4@(0,d2),a0@		| Translate nibble and write
   1168  1.1.2.1  scottr 
   1169      1.1  scottr 	/*
   1170      1.1  scottr 	 * XXX We have a classic off-by-one error here: the last access
   1171      1.1  scottr 	 * reaches beyond the data buffer which bombs with memory
   1172      1.1  scottr 	 * protection. The value read isn't used anyway...
   1173      1.1  scottr 	 * Hopefully there is enough time for an additional check
   1174      1.1  scottr 	 * (exit the last loop cycle before the buffer access).
   1175      1.1  scottr 	 */
   1176      1.1  scottr 	tstl	d4			| Last loop cycle?
   1177      1.1  scottr 	beq	wsSDDone		| Then get out while we can.
   1178      1.1  scottr 
   1179      1.1  scottr 	moveb	a3@+,d2			| Get third byte
   1180      1.1  scottr 	tstw	d4			| First write tag buffer,...
   1181      1.1  scottr 	bne	wsData
   1182      1.1  scottr 
   1183      1.1  scottr 	swap	d4			| ...then write data buffer
   1184      1.1  scottr 	bne	wsSD1
   1185      1.1  scottr 
   1186      1.1  scottr 	/*
   1187      1.1  scottr 	 * Write nibbles for last 2 bytes, then
   1188      1.1  scottr 	 * split checksum bytes in 6&2 and write them to disk
   1189      1.1  scottr 	 */
   1190      1.1  scottr wsSDDone:
   1191      1.1  scottr 	clrb	d3			| No 513th byte
   1192      1.1  scottr 	lsrw	#6,d3			| Set up 2 bit nibbles
   1193      1.1  scottr wsRDY05:
   1194      1.1  scottr 	tstb	a2@			| IWM ready?
   1195      1.1  scottr 	bpl	wsRDY05
   1196      1.1  scottr 	moveb	a4@(0,d3),a0@		| Write fragments
   1197      1.1  scottr 	moveb	d5,d3
   1198      1.1  scottr 	rolw	#2,d3
   1199      1.1  scottr 	moveb	d6,d3
   1200      1.1  scottr 	rolw	#2,d3
   1201      1.1  scottr 	andib	#0x3F,d0
   1202      1.1  scottr wsRDY06:
   1203      1.1  scottr 	tstb	a2@			| IWM ready?
   1204      1.1  scottr 	bpl	wsRDY06
   1205      1.1  scottr 	moveb	a4@(0,d0),a0@		| Write 511th byte
   1206      1.1  scottr 	andib	#0x3F,d1
   1207      1.1  scottr wsRDY07:
   1208      1.1  scottr 	tstb	a2@			| IWM ready?
   1209      1.1  scottr 	bpl	wsRDY07
   1210      1.1  scottr 	moveb	a4@(0,d1),a0@		| write 512th byte
   1211      1.1  scottr 	moveb	d7,d3
   1212      1.1  scottr 	lsrw	#6,d3			| Get fragments ready
   1213      1.1  scottr wsRDY08:
   1214      1.1  scottr 	tstb	a2@			| IWM ready?
   1215      1.1  scottr 	bpl	wsRDY08
   1216      1.1  scottr 	moveb	a4@(0,d3),a0@		| Write fragments
   1217      1.1  scottr 	andib	#0x3F,d5
   1218      1.1  scottr wsRDY09:
   1219      1.1  scottr 	tstb	a2@			| IWM ready?
   1220      1.1  scottr 	bpl	wsRDY09
   1221      1.1  scottr 	moveb	a4@(0,d5),a0@		| Write first checksum byte
   1222      1.1  scottr 	andib	#0x3F,D6
   1223      1.1  scottr wsRDY10:
   1224      1.1  scottr 	tstb	a2@			| IWM ready?
   1225      1.1  scottr 	bpl	wsRDY10
   1226      1.1  scottr 	moveb	a4@(0,d6),a0@		| Write second checksum byte
   1227      1.1  scottr 	andib	#0x3F,d7
   1228      1.1  scottr wsRDY11:
   1229      1.1  scottr 	tstb	a2@			| IWM ready?
   1230      1.1  scottr 	bpl	wsRDY11
   1231      1.1  scottr 	moveb	a4@(0,d7),a0@		| Write third checksum byte
   1232      1.1  scottr 
   1233      1.1  scottr 	/*
   1234      1.1  scottr 	 * Write sector data lead-out
   1235      1.1  scottr 	 */
   1236      1.1  scottr 	lea	dataLeadOut,a4		| Sector data lead-out
   1237      1.1  scottr 	moveq	#3,d2			| Four bytes long {3,2,1,0}
   1238      1.1  scottr wsLeadOut:
   1239      1.1  scottr 	moveb	a2@,d1			| IWM ready?
   1240      1.1  scottr 	bpl	wsLeadOut
   1241      1.1  scottr 	moveb	a4@+,a0@		| Write lead-out
   1242      1.1  scottr 	dbf	d2,wsLeadOut
   1243      1.1  scottr 
   1244      1.1  scottr 	moveq	#0,d0
   1245      1.1  scottr 	btst	#6,d1			| Check IWM underrun bit
   1246      1.1  scottr 	bne	wsNoErr
   1247      1.1  scottr 
   1248      1.1  scottr 	moveq	#wrUnderRun,d0		| Could not write
   1249      1.1  scottr 					| fast enough to keep up with IWM
   1250      1.1  scottr wsNoErr:
   1251      1.1  scottr 	tstb	a0@(0x0200)		| q7L -- Write OFF
   1252      1.1  scottr 
   1253      1.1  scottr wsDone:
   1254  1.1.2.1  scottr 	tstb	d0			| Any error? Simply retry
   1255  1.1.2.1  scottr 	bne	wsBufInvalid
   1256  1.1.2.1  scottr 
   1257  1.1.2.1  scottr 	movel	a6@(-10),a4		| Else, get ptr to current slot
   1258  1.1.2.1  scottr 	clrl	a4@(o_valid)		| Mark current buffer "clean"
   1259  1.1.2.1  scottr 	bra	wsNextSect
   1260  1.1.2.1  scottr 
   1261  1.1.2.1  scottr wsBufInvalid:
   1262  1.1.2.1  scottr 	subqb	#1,a6@(-6)		| retries
   1263  1.1.2.1  scottr 	bne	wsNextSect
   1264  1.1.2.1  scottr 					| Sector not found, but
   1265  1.1.2.1  scottr 	tstb	d0			| don't set error code if we
   1266  1.1.2.1  scottr 	bne	wsAllDone		| already have one.
   1267  1.1.2.1  scottr 	moveq	#sectNFErr,d0
   1268  1.1.2.1  scottr 
   1269  1.1.2.1  scottr wsAllDone:
   1270      1.1  scottr 	movew	a6@(-2),sr		| Restore interrupt mask
   1271      1.1  scottr 	moveml	sp@+,d1-d7/a0-a5
   1272      1.1  scottr 	unlk	a6
   1273      1.1  scottr 	rts
   1274      1.1  scottr 
   1275      1.1  scottr 
   1276      1.1  scottr 
   1277      1.1  scottr /**
   1278      1.1  scottr  **	Local functions
   1279      1.1  scottr  **/
   1280      1.1  scottr 
   1281      1.1  scottr /*
   1282      1.1  scottr  * iwmDelay
   1283      1.1  scottr  *
   1284      1.1  scottr  * In-kernel calls to delay() in mac68k/clock.c bomb
   1285      1.1  scottr  *
   1286      1.1  scottr  * Parameters:	d0	delay in milliseconds
   1287      1.1  scottr  * Trashes:	d0, d1
   1288      1.1  scottr  * Returns:	-
   1289      1.1  scottr  */
   1290      1.1  scottr iwmDelay:
   1291      1.1  scottr 	/* TimeDBRA is ~8K for 040/33 machines, so we need nested loops */
   1292      1.1  scottr id00:	movew	_TimeDBRA,d1		| dbra loops per ms
   1293      1.1  scottr id01:	dbra	d1,id01			|
   1294      1.1  scottr 	dbra	d0,id00
   1295      1.1  scottr 	rts
   1296      1.1  scottr 
   1297      1.1  scottr 
   1298      1.1  scottr /*
   1299      1.1  scottr  * selDriveReg -- Select drive status/control register
   1300      1.1  scottr  *
   1301      1.1  scottr  * Parameters:	d0	register #
   1302      1.1  scottr  *			(bit 0 - CA2, bit 1 - SEL, bit 2 - CA0, bit 3 - CA1)
   1303      1.1  scottr  *		a0	IWM base address
   1304      1.1  scottr  *		a1	VIA base address
   1305      1.1  scottr  * Returns:	d0	register # (unchanged)
   1306      1.1  scottr  */
   1307      1.1  scottr selDriveReg:
   1308      1.1  scottr 	tstb	a0@(ph0H)		| default CA0 to 1 (says IM III)
   1309      1.1  scottr 	tstb	a0@(ph1H)		| default CA1 to 1
   1310      1.1  scottr 
   1311      1.1  scottr 	btst	#0,d0			| bit 0 set => CA2 on
   1312      1.1  scottr 	beq	se00
   1313      1.1  scottr 	tstb	a0@(ph2H)
   1314      1.1  scottr 	bra	se01
   1315      1.1  scottr se00:
   1316      1.1  scottr 	tstb	a0@(ph2L)
   1317      1.1  scottr 
   1318      1.1  scottr se01:
   1319      1.1  scottr 	btst	#1,d0			| bit 1 set => SEL on (VIA 1)
   1320      1.1  scottr 	beq	se02
   1321      1.1  scottr 	bset	#vHeadSel,a1@(vBufA)
   1322      1.1  scottr 	bra	se03
   1323      1.1  scottr se02:
   1324      1.1  scottr 	bclr	#vHeadSel,a1@(vBufA)
   1325      1.1  scottr 
   1326      1.1  scottr se03:
   1327      1.1  scottr 	btst	#2,d0			| bit 2 set => CA0 on
   1328      1.1  scottr 	bne	se04
   1329      1.1  scottr 	tstb	a0@(ph0L)
   1330      1.1  scottr 
   1331      1.1  scottr se04:
   1332      1.1  scottr 	btst	#3,d0			| bit 3 set => CA1 on
   1333      1.1  scottr 	bne	se05
   1334      1.1  scottr 	tstb	a0@(ph1L)
   1335      1.1  scottr se05:
   1336      1.1  scottr 	rts
   1337      1.1  scottr 
   1338      1.1  scottr 
   1339      1.1  scottr 
   1340      1.1  scottr /*
   1341      1.1  scottr  * dstatus -- check drive status (bit 7 - N flag) wrt. a previously
   1342      1.1  scottr  * set status tag.
   1343      1.1  scottr  *
   1344      1.1  scottr  * Parameters:	d0	register selector
   1345      1.1  scottr  *		a0	IWM base address
   1346      1.1  scottr  * Returns:	d0	status
   1347      1.1  scottr  */
   1348      1.1  scottr dstatus:
   1349      1.1  scottr 	tstb	a0@(q6H)
   1350      1.1  scottr 	moveb	a0@(q7L),d0
   1351      1.1  scottr 	tstb	a0@(q6L)		| leave in "read data reg"
   1352      1.1  scottr 	tstb	d0			| state for safety
   1353      1.1  scottr 
   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.1  scottr  * Parameters:	a0	IWMBase
   1361      1.1  scottr  *		a1	VIABase
   1362      1.1  scottr  *		d0	register selector
   1363      1.1  scottr  * Returns:	d0	status (Bit 7)
   1364      1.1  scottr  */
   1365      1.1  scottr driveStat:
   1366      1.1  scottr 	tstb	a0@(mtrOn)		| ENABLE; turn drive on
   1367      1.1  scottr 	bsr	selDriveReg
   1368      1.1  scottr 	bsr	dstatus
   1369      1.1  scottr 
   1370      1.1  scottr 	rts
   1371      1.1  scottr 
   1372      1.1  scottr 
   1373      1.1  scottr /*
   1374      1.1  scottr  * dtrigger -- toggle LSTRB line to give drive a strobe signal
   1375      1.1  scottr  * IM III says pulse length = 1 us < t < 1 ms
   1376      1.1  scottr  *
   1377      1.1  scottr  * Parameters:	a0	IWMBase
   1378      1.1  scottr  *		a1	VIABase
   1379      1.1  scottr  * Returns:	-
   1380      1.1  scottr  */
   1381      1.1  scottr dtrigger:
   1382      1.1  scottr 	tstb	a0@(ph3H)		| LSTRB high
   1383      1.1  scottr 	moveb	a1@(vBufA),a1@(vBufA)	| intelligent nop seen in q700 ROM
   1384      1.1  scottr 	tstb	a0@(ph3L)		| LSTRB low
   1385      1.1  scottr 
   1386      1.1  scottr 	rts
   1387      1.1  scottr 
   1388      1.1  scottr 
   1389      1.1  scottr /*
   1390      1.1  scottr  * driveCmd -- send command to drive.
   1391      1.1  scottr  *
   1392      1.1  scottr  * Parameters:	a0	IWMBase
   1393      1.1  scottr  *		a1	VIABase
   1394      1.1  scottr  *		d0	Command token
   1395      1.1  scottr  * Returns:	-
   1396      1.1  scottr  */
   1397      1.1  scottr driveCmd:
   1398      1.1  scottr 	bsr	selDriveReg
   1399      1.1  scottr 	bsr	dtrigger
   1400      1.1  scottr 
   1401      1.1  scottr 	rts
   1402      1.1  scottr 
   1403      1.1  scottr 
   1404      1.1  scottr /*
   1405      1.1  scottr  * readSectHdr -- read and decode the next available sector header.
   1406      1.1  scottr  *
   1407      1.1  scottr  * TODO:	Poll SCC as long as interrupts are disabled.
   1408      1.1  scottr  *
   1409  1.1.2.1  scottr  * Parameters:	a4	sectorHdr_t address
   1410      1.1  scottr  * Returns:	d0	result code
   1411  1.1.2.1  scottr  * Uses:	d0-d4, a0, a2-a4
   1412      1.1  scottr  */
   1413      1.1  scottr readSectHdr:
   1414      1.1  scottr 	moveq	#3,d4			| Read 3 chars from IWM for sync
   1415      1.1  scottr 	movew	#600,d3			| Retries to sync to disk
   1416      1.1  scottr 	moveq	#0,d2			| Clear scratch regs
   1417      1.1  scottr 	moveq	#0,d1
   1418      1.1  scottr 	moveq	#0,d0
   1419  1.1.2.1  scottr  	movel	_IWMBase,a0		| IWM base address
   1420      1.1  scottr 
   1421      1.1  scottr 	tstb	a0@(q7L)
   1422      1.1  scottr 	lea	a0@(q6L),a0		| IWM data register
   1423      1.1  scottr shReadSy:
   1424      1.1  scottr 	moveb	a0@,d2			| Read char
   1425      1.1  scottr 	dbra	d3,shSeekSync
   1426      1.1  scottr 
   1427      1.1  scottr 	moveq	#noNybErr,d0		| Disk is blank?
   1428      1.1  scottr 	bra	shDone
   1429      1.1  scottr 
   1430      1.1  scottr shSeekSync:
   1431      1.1  scottr 	bpl	shReadSy		| No char at IWM, repeat read
   1432      1.1  scottr 	subqw	#1,d4
   1433      1.1  scottr 	bne	shReadSy
   1434      1.1  scottr 	/*
   1435      1.1  scottr 	 * When we get here, the IWM should be in sync with the data
   1436      1.1  scottr 	 * stream from disk.
   1437      1.1  scottr 	 * Next look for sector header lead-in 'D5 AA 96'
   1438      1.1  scottr 	 */
   1439      1.1  scottr 	movew	#1500,d3		| Retries to seek header
   1440      1.1  scottr shLeadIn:
   1441      1.1  scottr 	lea	hdrLeadIn,a3		| Sector header lead-in bytes
   1442      1.1  scottr 	moveq	#0x03,d4		| is 3 bytes long
   1443      1.1  scottr shLI1:
   1444      1.1  scottr 	moveb	a0@,d2			| Get next byte
   1445  1.1.2.1  scottr 	bpl	shLI1			| No char at IWM, repeat read
   1446      1.1  scottr 	dbra	d3,shLI2
   1447      1.1  scottr 	moveq	#noAdrMkErr,d0		| Can't find an address mark
   1448      1.1  scottr 	bra	shDone
   1449      1.1  scottr 
   1450      1.1  scottr shLI2:
   1451      1.1  scottr 	cmpb	a3@+,d2
   1452      1.1  scottr 	bne	shLeadIn		| If ne restart scan
   1453      1.1  scottr 	subqw	#1,d4
   1454      1.1  scottr 	bne	shLI1
   1455      1.1  scottr 	/*
   1456      1.1  scottr 	 * We have found the lead-in. Now get the header information.
   1457      1.1  scottr 	 * Reg d4 holds the checksum.
   1458      1.1  scottr 	 */
   1459      1.1  scottr 	lea	diskTo-0x90,a2		| Translate disk bytes -> 6&2
   1460      1.1  scottr shHdr1:
   1461      1.1  scottr 	moveb	a0@,d0			| Get 1st char
   1462      1.1  scottr 	bpl	shHdr1
   1463      1.1  scottr 	moveb	a2@(0,d0),d1		| and remap it
   1464      1.1  scottr 	moveb	d1,d4
   1465      1.1  scottr 	rorw	#6,d1			| separate 2:6, drop hi bits
   1466      1.1  scottr shHdr2:
   1467      1.1  scottr 	moveb	a0@,d0			| Get 2nd char
   1468      1.1  scottr 	bpl	shHdr2
   1469      1.1  scottr 	moveb	a2@(0,d0),d2		| and remap it
   1470      1.1  scottr 	eorb	d2,d4
   1471      1.1  scottr shHdr3:
   1472      1.1  scottr 	moveb	a0@,d0			| Get 3rd char
   1473      1.1  scottr 	bpl	shHdr3
   1474      1.1  scottr 	moveb	a2@(0,d0),d1		| and remap it
   1475      1.1  scottr 	eorb	d1,d4
   1476      1.1  scottr 	rolw	#6,d1			|
   1477      1.1  scottr shHdr4:
   1478      1.1  scottr 	moveb	a0@,d0			| Get 4th char
   1479      1.1  scottr 	bpl	shHdr4
   1480      1.1  scottr 	moveb	a2@(0,d0),d3		| and remap it
   1481      1.1  scottr 	eorb	d3,d4
   1482      1.1  scottr shHdr5:
   1483      1.1  scottr 	moveb	a0@,d0			| Get checksum byte
   1484      1.1  scottr 	bpl	shHdr5
   1485      1.1  scottr 	moveb	a2@(0,d0),d5		| and remap it
   1486      1.1  scottr 	eorb	d5,d4
   1487      1.1  scottr 	bne	shCsErr			| Checksum ok?
   1488      1.1  scottr 	/*
   1489      1.1  scottr 	 * We now have in
   1490      1.1  scottr 	 * d1/lsb	track number
   1491      1.1  scottr 	 * d1/msb	bit 3 is side bit
   1492      1.1  scottr 	 * d2		sector number
   1493      1.1  scottr 	 * d3		???
   1494      1.1  scottr 	 * d5		checksum (=0)
   1495      1.1  scottr 	 *
   1496      1.1  scottr 	 * Next check for lead-out.
   1497      1.1  scottr 	 */
   1498      1.1  scottr 	moveq	#1,d4			| is 2 bytes long
   1499      1.1  scottr shHdr6:
   1500      1.1  scottr 	moveb	a0@,d0			| Get token
   1501      1.1  scottr 	bpl	shHdr6
   1502      1.1  scottr 	cmpb	a3@+,d0			| Check
   1503      1.1  scottr 	bne	shLOErr			| Fault!
   1504      1.1  scottr 	dbra	d4,shHdr6
   1505      1.1  scottr 	movew	d1,d0			| Isolate side bit
   1506      1.1  scottr 	lsrw	#8,d0
   1507      1.1  scottr 	moveb	d0,a4@+			| and store it
   1508      1.1  scottr 	moveb	d1,a4@+			| Store track number
   1509      1.1  scottr 	moveb	d2,a4@+			| and sector number
   1510      1.1  scottr 	moveq	#0,d0			| All is well
   1511      1.1  scottr 	bra	shDone
   1512      1.1  scottr 
   1513      1.1  scottr shCsErr:
   1514      1.1  scottr 	moveq	#badCkSmErr,d0		| Bad sector header checksum
   1515      1.1  scottr 	bra	shDone
   1516      1.1  scottr shLOErr:
   1517      1.1  scottr 	moveq	#badBtSlpErr,d0		| Bad address mark (no lead-out)
   1518      1.1  scottr 
   1519      1.1  scottr shDone:
   1520      1.1  scottr 	tstl	d0			| Set flags
   1521      1.1  scottr 	rts
   1522