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