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