1/* $NetBSD: iwm.s,v 1.3 2001/11/20 03:19:44 chs Exp $ */ 2 3/* 4 * Copyright (c) 1996-99 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 We run at spl4 to give the NMI switch a chance. All currently 50 * supported machines have no interrupt sources > 4 (SSC) -- the 51 * Q700 interrupt levels can be shifted around in A/UX mode, 52 * but we're not there, yet. 53 * 54 * o As a special case iwmReadSectHdr() must run with interrupts disabled 55 * (it transfers data). Depending on the needs of the caller, it 56 * may be necessary to block interrupts after completion of the routine 57 * so interrupt handling is left to the caller. 58 * 59 * If we wanted to deal with incoming serial data / serial interrupts, 60 * we would have to either call zshard(0) {mac68k/dev/zs.c} or 61 * zsc_intr_hard(0) {sys/dev/ic/z8530sc.c}. Or we would have to roll our 62 * own as both of the listed function calls look rather expensive compared 63 * to a 'tst.b REGADDR ; bne NN'. 64 */ 65 66#include <m68k/asm.h> 67 68#include <mac68k/obio/iwmreg.h> 69 70#define USE_DELAY 0 /* "1" bombs for unknown reasons */ 71 72 73/* 74 * References to global name space 75 */ 76 .extern _C_LABEL(TimeDBRA) | in mac68k/macrom.c 77 .extern _C_LABEL(Via1Base) | in mac68k/machdep.c 78 .extern _C_LABEL(IWMBase) | in iwm_fd.c 79 80 81 .data 82 83diskTo: 84 /* 85 * Translation table from 'disk bytes' to 6 bit 'nibbles', 86 * taken from the .Sony driver. 87 * This could be made a loadable table (via ioctls) to read 88 * e.g. ProDOS disks (there is a hook for such a table in .Sony). 89 */ 90 .byte /* 90 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01 91 .byte /* 98 */ 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, 0x05, 0x06 92 .byte /* A0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x08 93 .byte /* A8 */ 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, 0x0C, 0x0D 94 .byte /* B0 */ 0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13 95 .byte /* B8 */ 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A 96 .byte /* C0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 97 .byte /* C8 */ 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, 0x1D, 0x1E 98 .byte /* D0 */ 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0x20, 0x21 99 .byte /* D8 */ 0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28 100 .byte /* E0 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, 0x2A, 0x2B 101 .byte /* E8 */ 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32 102 .byte /* F0 */ 0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38 103 .byte /* F8 */ 0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F 104 105hdrLeadIn: 106 .byte 0xD5, 0xAA, 0x96 107 108hdrLeadOut: 109 .byte 0xDE, 0xAA, 0xFF 110 111dataLeadIn: 112 .byte 0xD5, 0xAA, 0xAD 113 114dataLeadOut: 115 .byte 0xDE, 0xAA, 0xFF, 0xFF 116 117 118toDisk: 119 /* 120 * Translation table from 6-bit nibbles [0x00..0x3f] to 'disk bytes' 121 */ 122 .byte /* 00 */ 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6 123 .byte /* 08 */ 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3 124 .byte /* 10 */ 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC 125 .byte /* 18 */ 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3 126 .byte /* 20 */ 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE 127 .byte /* 28 */ 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC 128 .byte /* 30 */ 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xf5, 0xF6 129 .byte /* 38 */ 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 130 131syncPattern: 132 /* 133 * This sync pattern creates 4 sync chars with 10 bits each that look 134 * like 0011111111b (i.e. 0x0FF). As the IWM ignores leading zero 135 * bits, it locks on 0xFF after the third sync byte. 136 * For convenience, the bytes of the sector data lead-in 137 * (D5 AA AD) follow. 138 */ 139 .byte 0xFF, 0x3F, 0xCF, 0xF3, 0xFC, 0xFF 140 .byte 0xD5, 0xAA, 0xAD 141 142 143 144 .text 145 146/* 147 * Register conventions: 148 * %a0 IWM base address 149 * %a1 VIA1 base address 150 * 151 * %d0 return value (0 == no error) 152 * 153 * Upper bits in data registers that are not cleared give nasty 154 * (pseudo-) random errors when building an address. Make sure those 155 * registers are cleaned with a moveq before use! 156 */ 157 158 159 160/** 161 ** Export wrappers 162 **/ 163 164/* 165 * iwmQueryDrvFlags -- export wrapper for driveStat 166 * 167 * Parameters: stack l drive selector 168 * stack l register selector 169 * Returns: %d0 flag 170 */ 171ENTRY(iwmQueryDrvFlag) 172 link %a6,#0 173 moveml %d1/%a0-%a1,%sp@- 174 movel _C_LABEL(IWMBase),%a0 175 movel _C_LABEL(Via1Base),%a1 176 177 movel %a6@(8),%d0 | Get drive # 178 beq quDrv00 179 cmpl #1,%d0 180 beq quDrv01 181 182 bra quDone | Invalid drive # 183 184quDrv00: 185 tstb %a0@(intDrive) | SELECT; choose drive #0 186 bra queryDrv 187 188quDrv01: 189 tstb %a0@(extDrive) | SELECT; choose drive #1 190 191queryDrv: 192 movel %a6@(12),%d0 | Get register # 193 bsr driveStat 194 195quDone: 196 moveml %sp@+,%d1/%a0-%a1 197 unlk %a6 198 rts 199 200 201/* 202 * iwmReadSectHdr -- read and decode the next available sector header. 203 * 204 * Parameters: stack l Address of sector header struct (I/O) 205 * b side (0, 1) 206 * b track (0..79) 207 * b sector (0..11) 208 * Returns: %d0 result code 209 */ 210ENTRY(iwmReadSectHdr) 211 link %a6,#0 212 moveml %d1-%d5/%a0-%a4,%sp@- 213 movel %a6@(0x08),%a4 | Get param block address 214 bsr readSectHdr 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 */ 231ENTRY(iwmInit) 232 link %a6,#0 233 moveml %d2/%a0,%sp@- 234 movel _C_LABEL(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 #iwmMode,%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 262initLp: 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 #iwmMode,%d0 274 beq initDone 275 moveb #iwmMode,%a0@(q7H) | Init IWM 276 tstb %a0@(q7L) 277 bra initLp 278 279initDone: 280 tstb %a0@(q6L) | Prepare IWM for data 281 moveq #0,%d0 | noErr 282 283initErr: 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 */ 301ENTRY(iwmCheckDrive) 302 link %a6,#0 303 moveml %d1/%a0-%a1,%sp@- 304 movel _C_LABEL(IWMBase),%a0 305 movel _C_LABEL(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 316chkDrv00: 317 tstb %a0@(intDrive) | SELECT; choose drive #0 318 bra chkDrive 319 320chkDrv01: 321 tstb %a0@(extDrive) | SELECT; choose drive #1 322 323chkDrive: 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. 342chkHasDisk: 343 moveq #diskInserted,%d0 | Disk inserted? 344 bsr driveStat 345 bpl chkMotorOn 346 bset #1,%d1 | 1 = No. 347 bra chkDone 348chkMotorOn: 349 moveq #drvMotorState,%d0 | Motor is running? 350 bsr driveStat 351 bpl chkWrtProt 352 bset #2,%d1 | 1 = No. 353chkWrtProt: 354 moveq #writeProtected,%d0 | Disk is write protected? 355 bsr driveStat 356 bpl chkDD_HD 357 bset #3,%d1 | 1 = No. 358chkDD_HD: 359 moveq #diskIsHD,%d0 | Disk is HD? (was "drive installed") 360 bsr driveStat 361 bpl chkDone 362 bset #4,%d1 | 1 = No. 363chkDone: 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 */ 381ENTRY(iwmDiskEject) 382 link %a6,#0 383 movel _C_LABEL(IWMBase),%a0 384 movel _C_LABEL(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 393ejDrv00: 394 tstb %a0@(intDrive) | SELECT; choose drive #0 395 bra ejDisk 396 397ejDrv01: 398 tstb %a0@(extDrive) | SELECT; choose drive #1 399ejDisk: 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... 423ejDone: 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 */ 434ENTRY(iwmSelectDrive) 435 link %a6,#0 436 moveml %a0-%a1,%sp@- 437 movel _C_LABEL(IWMBase),%a0 438 movel _C_LABEL(Via1Base),%a1 439 440 movel %a6@(8),%d0 | Get drive # 441 bne extDrv 442 tstb %a0@(intDrive) 443 bra sdDone 444extDrv: 445 tstb %a0@(extDrive) 446sdDone: 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 */ 459ENTRY(iwmMotor) 460 link %a6,#0 461 moveml %a0-%a1,%sp@- 462 movel _C_LABEL(IWMBase),%a0 463 movel _C_LABEL(Via1Base),%a1 464 465 movel %a6@(8),%d0 | Get drive # 466 bne mtDrv1 467 tstb %a0@(intDrive) 468 bra mtSwitch 469mtDrv1: 470 tstb %a0@(extDrive) 471mtSwitch: 472 movel #motorOnCmd,%d0 | Motor ON 473 tstl %a6@(12) 474 bne mtON 475 movel #motorOffCmd,%d0 476mtON: 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 */ 492ENTRY(iwmSelectSide) 493 link %a6,#0 494 moveml %d1/%a0-%a1,%sp@- 495 movel _C_LABEL(IWMBase),%a0 496 movel _C_LABEL(Via1Base),%a1 497 498 moveq #0x0B,%d0 | Drive ready for reading? 499 bsr selDriveReg | (undocumented) 500ss01: 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 508ssSide0: 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 */ 524ENTRY(iwmTrack00) 525 link %a6,#0 526 moveml %d1-%d4/%a0-%a1,%sp@- 527 movel _C_LABEL(IWMBase),%a0 528 movel _C_LABEL(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 537t0Retry: 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 545t0Still: 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 555t002: 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 571isTrack00: 572 moveq #0,%d0 573t0Done: 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 */ 585ENTRY(iwmSeek) 586 link %a6,#0 587 moveml %d1-%d4/%a0-%a1,%sp@- 588 movel _C_LABEL(IWMBase),%a0 589 movel _C_LABEL(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 601stepOut: 602 subql #1,%d2 | Loop exits for -1 603 bsr driveCmd | Set direction 604stLoop: 605 moveq #doStepCmd,%d0 606 bsr driveCmd | Step one! 607 movew #80,%d4 | Retries 608st01: 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 618st02: 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 _C_LABEL(TimeDBRA),%d4 | dbra loops per ms 626 lsrw #5,%d4 | DIV 32 627st03: dbra %d4,st03 | makes ca. 30 us 628#endif 629 630 dbra %d2,stLoop 631 632 moveq #0,%d2 | All is well 633stDone: 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 * XXX make "sizeof cylCache_t" a symbolic constant 648 * 649 * Parameters: %fp+08 l Address of sector data buffer (512 bytes) 650 * %fp+12 l Address of sector header struct (I/O) 651 * %fp+16 l Address of cache buffer ptr array 652 * Returns: %d0 result code 653 * Local: %fp-2 w CPU status register 654 * %fp-3 b side, 655 * %fp-4 b track, 656 * %fp-5 b sector wanted 657 * %fp-6 b retry count 658 * %fp-7 b sector read 659 */ 660ENTRY(iwmReadSector) 661 link %a6,#-8 662 moveml %d1-%d7/%a0-%a5,%sp@- 663 664 movel _C_LABEL(Via1Base),%a1 665 movel %a6@(o_hdr),%a4 | Addr of sector header struct 666 667 moveb %a4@+,%a6@(-3) | Save side bit, 668 moveb %a4@+,%a6@(-4) | track#, 669 moveb %a4@,%a6@(-5) | sector# 670 moveb #2*maxGCRSectors,%a6@(-6) | Max. retry count 671 672 movew %sr,%a6@(-2) | Save CPU status register 673 oriw #0x0600,%sr | Block all interrupts 674 675rsNextSect: 676 movel %a6@(o_hdr),%a4 | Addr of sector header struct 677 bsr readSectHdr | Get next available SECTOR header 678 bne rsDone | Return if error 679 680 /* 681 * Is this the right track & side? If not, return with error 682 */ 683 movel %a6@(o_hdr),%a4 | Sector header struct 684 685 moveb %a4@(o_side),%d1 | Get actual side 686 lsrb #3,%d1 | "Normalize" side bit (to bit 0) 687 andb #1,%d1 688 moveb %a6@(-3),%d2 | Get wanted side 689 eorb %d1,%d2 | Compare side bits 690 bne rsSeekErr | Should be equal! 691 692 moveb %a6@(-4),%d1 | Get track# we want 693 cmpb %a4@(o_track),%d1 | Compare to the header we've read 694 beq rsGetSect 695 696rsSeekErr: 697 moveq #seekErr,%d0 | Wrong track or side found 698 bra rsDone 699 700 /* 701 * Check for sector data lead-in 'D5 AA AD' 702 * Registers: 703 * %a0 points to data register of IWM as set up by readSectHdr 704 * %a2 points to 'diskTo' translation table 705 * %a4 points to tags buffer 706 */ 707rsGetSect: 708 moveb %a4@(2),%a6@(-7) | save sector number 709 lea %a4@(3),%a4 | Beginning of tag buffer 710 moveq #50,%d3 | Max. retries for sector lookup 711rsLeadIn: 712 lea dataLeadIn,%a3 | Sector data lead-in 713 moveq #0x03,%d4 | is 3 bytes long 714rsLI1: 715 moveb %a0@,%d2 | Get next byte 716 bpl rsLI1 717 dbra %d3,rsLI2 718 moveq #noDtaMkErr,%d0 | Can't find a data mark 719 bra rsDone 720 721rsLI2: 722 cmpb %a3@+,%d2 723 bne rsLeadIn | If ne restart scan 724 subqw #1,%d4 725 bne rsLI1 726 727 /* 728 * We have found the lead-in. Now get the 12 tag bytes. 729 * (We leave %a3 pointing to 'dataLeadOut' for later.) 730 */ 731rsTagNyb0: 732 moveb %a0@,%d3 | Get a char, 733 bpl rsTagNyb0 734 moveb %a2@(0,%d3),%a4@+ | remap and store it 735 736 moveq #0,%d5 | Clear checksum registers 737 moveq #0,%d6 738 moveq #0,%d7 739 moveq #10,%d4 | Loop counter 740 moveq #0,%d3 | Data scratch reg 741 742rsTags: 743rsTagNyb1: 744 moveb %a0@,%d3 | Get 2 bit nibbles 745 bpl rsTagNyb1 746 moveb %a2@(0,%d3),%d1 | Remap disk byte 747 rolb #2,%d1 748 moveb %d1,%d2 749 andib #0xC0,%d2 | Get top 2 bits for first byte 750rsTagNyb2: 751 moveb %a0@,%d3 | Get first 6 bit nibble 752 bpl rsTagNyb2 753 orb %a2@(0,%d3),%d2 | Remap it and complete first byte 754 755 moveb %d7,%d3 | The X flag bit (a copy of the carry 756 addb %d7,%d3 | flag) is added with the next addx 757 758 rolb #1,%d7 759 eorb %d7,%d2 760 moveb %d2,%a4@+ | Store tag byte 761 addxb %d2,%d5 | See above 762 763 rolb #2,%d1 764 moveb %d1,%d2 765 andib #0xC0,%d2 | Get top 2 bits for second byte 766rsTagNyb3: 767 moveb %a0@,%d3 | Get second 6 bit nibble 768 bpl rsTagNyb3 769 orb %a2@(0,%d3),%d2 | remap it and complete byte 770 eorb %d5,%d2 771 moveb %d2,%a4@+ | Store tag byte 772 addxb %d2,%d6 773 774 rolb #2,%d1 775 andib #0xC0,%d1 | Get top 2 bits for third byte 776rsTagNyb4: 777 moveb %a0@,%d3 | Get third 6 bit nibble 778 bpl rsTagNyb4 779 orb %a2@(0,%d3),%d1 | remap it and complete byte 780 eorb %d6,%d1 781 moveb %d1,%a4@+ | Store tag byte 782 addxb %d1,%d7 783 784 subqw #3,%d4 | Update byte counter (four 6&2 encoded 785 bpl rsTags | disk bytes make three data bytes). 786 787 /* 788 * Jetzt sind wir hier... 789 * ...und Thomas D. hat noch was zu sagen... 790 * 791 * We begin to read in the actual sector data. 792 * Compare sector # to what we wanted: If it matches, read directly 793 * to buffer, else read to track cache. 794 */ 795 movew #0x01FE,%d4 | Loop counter 796 moveq #0,%d1 | Clear %d1 797 moveb %a6@(-7),%d1 | Get sector# we have read 798 cmpb %a6@(-5),%d1 | Compare to the sector# we want 799 bne rsToCache 800 movel %a6@(o_buf),%a4 | Sector data buffer 801 bra rsData 802rsToCache: 803 movel %a6@(o_rslots),%a4 | Base address of slot array 804 lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes 805 movel #-1,%a4@(o_valid,%d1) 806 movel %a4@(o_secbuf,%d1),%a4 | and get its buffer ptr 807rsData: 808rsDatNyb1: 809 moveb %a0@,%d3 | Get 2 bit nibbles 810 bpl rsDatNyb1 811 moveb %a2@(0,%d3),%d1 | Remap disk byte 812 rolb #2,%d1 813 moveb %d1,%d2 814 andib #0xC0,%d2 | Get top 2 bits for first byte 815rsDatNyb2: 816 moveb %a0@,%d3 | Get first 6 bit nibble 817 bpl rsDatNyb2 818 orb %a2@(0,%d3),%d2 | Remap it and complete first byte 819 820 moveb %d7,%d3 | The X flag bit (a copy of the carry 821 addb %d7,%d3 | flag) is added with the next addx 822 823 rolb #1,%d7 824 eorb %d7,%d2 825 moveb %d2,%a4@+ | Store data byte 826 addxb %d2,%d5 | See above 827 828 rolb #2,%d1 829 moveb %d1,%d2 830 andib #0xC0,%d2 | Get top 2 bits for second byte 831rsDatNyb3: 832 moveb %a0@,%d3 | Get second 6 bit nibble 833 bpl rsDatNyb3 834 orb %a2@(0,%d3),%d2 | Remap it and complete byte 835 eorb %d5,%d2 836 moveb %d2,%a4@+ | Store data byte 837 addxb %d2,%d6 838 tstw %d4 839 beq rsCkSum | Data read, continue with checksums 840 841 rolb #2,%d1 842 andib #0xC0,%d1 | Get top 2 bits for third byte 843rsDatNyb4: 844 moveb %a0@,%d3 | Get third 6 bit nibble 845 bpl rsDatNyb4 846 orb %a2@(0,%d3),%d1 | Remap it and complete byte 847 eorb %d6,%d1 848 moveb %d1,%a4@+ | Store data byte 849 addxb %d1,%d7 850 subqw #3,%d4 | Update byte counter 851 bra rsData 852 853 /* 854 * Next read checksum bytes 855 * While reading the sector data, three separate checksums are 856 * maintained in %D5/%D6/%D7 for the 1st/2nd/3rd data byte of 857 * each group. 858 */ 859rsCkSum: 860rsCkS1: 861 moveb %a0@,%d3 | Get 2 bit nibbles 862 bpl rsCkS1 863 moveb %a2@(0,%d3),%d1 | Remap disk byte 864 bmi rsBadCkSum | Fault! (Bad read) 865 rolb #2,%d1 866 moveb %d1,%d2 867 andib #0xC0,%d2 | Get top 2 bits for first byte 868rsCkS2: 869 moveb %a0@,%d3 | Get first 6 bit nibble 870 bpl rsCkS2 871 moveb %a2@(0,%d3),%d3 | and remap it 872 bmi rsBadCkSum | Fault! ( > 0x3f is bad read) 873 orb %d3,%d2 | Merge 6&2 874 cmpb %d2,%d5 | Compare first checksum to %D5 875 bne rsBadCkSum | Fault! (Checksum) 876 877 rolb #2,%d1 878 moveb %d1,%d2 879 andib #0xC0,%d2 | Get top 2 bits for second byte 880rsCkS3: 881 moveb %a0@,%d3 | Get second 6 bit nibble 882 bpl rsCkS3 883 moveb %a2@(0,%d3),%d3 | and remap it 884 bmi rsBadCkSum | Fault! (Bad read) 885 orb %d3,%d2 | Merge 6&2 886 cmpb %d2,%d6 | Compare second checksum to %D6 887 bne rsBadCkSum | Fault! (Checksum) 888 889 rolb #2,%d1 890 andib #0xC0,%d1 | Get top 2 bits for second byte 891rsCkS4: 892 moveb %a0@,%d3 | Get third 6 bit nibble 893 bpl rsCkS4 894 moveb %a2@(0,%d3),%d3 | and remap it 895 bmi rsBadCkSum | Fault! (Bad read) 896 orb %d3,%d1 | Merge 6&2 897 cmpb %d1,%d7 | Compare third checksum to %D7 898 beq rsLdOut | Fault! (Checksum) 899 900rsBadCkSum: 901 moveq #badDCkSum,%d0 | Bad data mark checksum 902 bra rsDone 903 904rsBadDBtSlp: 905 moveq #badDBtSlp,%d0 | One of the data mark bit slip 906 bra rsDone | nibbles was incorrect 907 908 /* 909 * We have gotten the checksums allright, now look for the 910 * sector data lead-out 'DE AA' 911 * (We have %a3 still pointing to 'dataLeadOut'; this part of the 912 * table is used for writing to disk, too.) 913 */ 914rsLdOut: 915 moveq #1,%d4 | Is two bytes long {1,0} 916rsLdOut1: 917 moveb %a0@,%d3 | Get token 918 bpl rsLdOut1 919 cmpb %a3@+,%d3 920 bne rsBadDBtSlp | Fault! 921 dbra %d4,rsLdOut1 922 moveq #0,%d0 | OK. 923 924 /* 925 * See if we got the sector we wanted. If not, and no error 926 * occurred, mark buffer valid. Else ignore the sector. 927 * Then, read on. 928 */ 929rsDone: 930 movel %a6@(o_hdr),%a4 | Addr of sector header struct 931 moveb %a4@(o_sector),%d1 | Get # of sector we have just read 932 cmpb %a6@(-5),%d1 | Compare to the sector we want 933 beq rsAllDone 934 935 tstb %d0 | Any error? Simply ignore data 936 beq rsBufValid 937 lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes 938 movel %a6@(o_rslots),%a4 939 clrl %a4@(o_valid,%d1) | Mark buffer content "invalid" 940 941rsBufValid: 942 subqb #1,%a6@(-6) | max. retries 943 bne rsNextSect 944 | Sector not found, but 945 tstb %d0 | don't set error code if we 946 bne rsAllDone | already have one. 947 moveq #sectNFErr,%d0 948rsAllDone: 949 movew %a6@(-2),%sr | Restore interrupt mask 950 moveml %sp@+,%d1-%d7/%a0-%a5 951 unlk %a6 952 rts 953 954 955/* 956 * iwmWriteSector -- encode and write data to the specified sector. 957 * 958 * TODO: Poll SCC as long as interrupts are disabled (see top comment) 959 * Understand and document the checksum algorithm! 960 * 961 * XXX Use registers more efficiently 962 * 963 * Parameters: %fp+8 l Address of sector header struct (I/O) 964 * %fp+12 l Address of cache buffer ptr array 965 * Returns: %d0 result code 966 * 967 * Local: %fp-2 w CPU status register 968 * %fp-3 b side, 969 * %fp-4 b track, 970 * %fp-5 b sector wanted 971 * %fp-6 b retry count 972 * %fp-10 b current slot 973 */ 974ENTRY(iwmWriteSector) 975 link %a6,#-10 976 moveml %d1-%d7/%a0-%a5,%sp@- 977 978 movel _C_LABEL(Via1Base),%a1 979 movel %a6@(o_hdr),%a4 | Addr of sector header struct 980 981 moveb %a4@+,%a6@(-3) | Save side bit, 982 moveb %a4@+,%a6@(-4) | track#, 983 moveb %a4@,%a6@(-5) | sector# 984 moveb #maxGCRSectors,%a6@(-6) | Max. retry count 985 986 movew %sr,%a6@(-2) | Save CPU status register 987 oriw #0x0600,%sr | Block all interrupts 988 989wsNextSect: 990 movel %a6@(o_hdr),%a4 991 bsr readSectHdr | Get next available sector header 992 bne wsAllDone | Return if error 993 994 /* 995 * Is this the right track & side? If not, return with error 996 */ 997 movel %a6@(o_hdr),%a4 | Sector header struct 998 999 moveb %a4@(o_side),%d1 | Get side# 1000 lsrb #3,%d1 | "Normalize" side bit... 1001 andb #1,%d1 1002 moveb %a6@(-3),%d2 | Get wanted side 1003 eorb %d1,%d2 | Compare side bits 1004 bne wsSeekErr 1005 1006 moveb %a6@(-4),%d1 | Get wanted track# 1007 cmpb %a4@(o_track),%d1 | Compare to the read header 1008 beq wsCompSect 1009 1010wsSeekErr: 1011 moveq #seekErr,%d0 | Wrong track or side 1012 bra wsAllDone 1013 1014 /* 1015 * Look up the current sector number in the cache. 1016 * If the buffer is dirty ("valid"), write it to disk. If not, 1017 * loop over all the slots and return if all of them are clean. 1018 * 1019 * Alternatively, we could decrement a "dirty sectors" counter here. 1020 */ 1021wsCompSect: 1022 moveq #0,%d1 | Clear register 1023 moveb %a4@(o_sector),%d1 | get the # of header read 1024 lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes 1025 movel %a6@(o_wslots),%a4 1026 tstl %a4@(o_valid,%d1) | Sector dirty? 1027 bne wsBufDirty 1028 1029 moveq #maxGCRSectors-1,%d2 | Any dirty sectors left? 1030wsChkDty: 1031 movew %d2,%d1 1032 lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes 1033 tstl %a4@(o_valid,%d1) 1034 bne wsNextSect | Sector dirty? 1035 dbra %d2,wsChkDty 1036 1037 bra wsAllDone | We are through with this track. 1038 1039 1040 /* 1041 * Write sync pattern and sector data lead-in 'D5 AA'. The 1042 * missing 'AD' is made up by piping 0x0B through the nibble 1043 * table (toDisk). 1044 * 1045 * To set up IWM for writing: 1046 * 1047 * access q6H & write first byte to q7H. 1048 * Then check bit 7 of q6L (status reg) for 'IWM ready' 1049 * and write subsequent bytes to q6H. 1050 * 1051 * Registers: 1052 * %a0 IWM base address (later: data register) 1053 * %a1 Via1Base 1054 * %a2 IWM handshake register 1055 * %a3 data (tags buffer, data buffer) 1056 * %a4 Sync pattern, 'toDisk' translation table 1057 */ 1058wsBufDirty: 1059 movel _C_LABEL(IWMBase),%a0 1060 lea %a4@(0,%d1),%a3 1061 movel %a3,%a6@(-10) | Save ptr to current slot 1062 tstb %a0@(q6H) | Enable writing to disk 1063 movel %a6@(o_hdr),%a4 | Sector header struct 1064 lea %a4@(o_Tags),%a3 | Point %a3 to tags buffer 1065 lea syncPattern,%a4 1066 1067 moveb %a4@+,%a0@(q7H) | Write first sync byte 1068 lea %a0@(q6L),%a2 | Point %a2 to handshake register 1069 lea %a0@(q6H),%a0 | Point %a0 to IWM data register 1070 1071 moveq #6,%d0 | Loop counter for sync bytes 1072 moveq #0,%d2 1073 moveq #0,%d3 1074 movel #0x02010009,%d4 | Loop counters for tag/sector data 1075 1076 /* 1077 * Write 5 sync bytes and first byte of sector data lead-in 1078 */ 1079wsLeadIn: 1080 moveb %a4@+,%d1 | Get next sync byte 1081wsLI1: 1082 tstb %a2@ | IWM ready? 1083 bpl wsLI1 1084 moveb %d1,%a0@ | Write it to disk 1085 subqw #1,%d0 1086 bne wsLeadIn 1087 1088 moveb %a4@+,%d1 | Write 2nd byte of sector lead-in 1089 lea toDisk,%a4 | Point %a4 to nibble translation table 1090wsLI2: 1091 tstb %a2@ | IWM ready? 1092 bpl wsLI2 1093 moveb %d1,%a0@ | Write it to disk 1094 1095 moveq #0,%d5 | Clear checksum registers 1096 moveq #0,%d6 1097 moveq #0,%d7 1098 1099 moveq #0x0B,%d1 | 3rd byte of sector data lead-in 1100 | (Gets translated to 0xAD) 1101 moveb %a3@+,%d2 | Get 1st byte from tags buffer 1102 bra wsDataEntry 1103 1104 /* 1105 * The following loop reads the content of the tags buffer (12 bytes) 1106 * and the data buffer (512 bytes). 1107 * Each pass reads out three bytes and 1108 * a) splits them 6&2 into three 6 bit nibbles and a fourth byte 1109 * consisting of the three 2 bit nibbles 1110 * b) encodes the nibbles with a table to disk bytes (bit 7 set, no 1111 * more than two consecutive zero bits) and writes them to disk as 1112 * 1113 * 00mmnnoo fragment 2 bit nibbles 1114 * 00mmmmmm 6 bit nibble -- first byte 1115 * 00nnnnnn 6 bit nibble -- second byte 1116 * 00oooooo 6 bit nibble -- third byte 1117 * 1118 * c) adds up three 8 bit checksums, one for each of the bytes written. 1119 */ 1120wsSD1: 1121 movel %a6@(-10),%a3 | Get ptr to current slot 1122 movel %a3@(o_secbuf),%a3 | Get start of sector data buffer 1123 1124wsData: 1125 addxb %d2,%d7 1126 eorb %d6,%d2 1127 moveb %d2,%d3 1128 lsrw #6,%d3 | Put 2 bit nibbles into place 1129wsRDY01: 1130 tstb %a2@ | IWM ready? 1131 bpl wsRDY01 1132 moveb %a4@(0,%d3),%a0@ | Translate nibble and write 1133 subqw #3,%d4 | Update counter 1134 moveb %d7,%d3 1135 addb %d7,%d3 | Set X flag (??) 1136 rolb #1,%d7 1137 andib #0x3F,%d0 1138wsRDY02: 1139 tstb %a2@ | IWM ready? 1140 bpl wsRDY02 1141 moveb %a4@(0,%d0),%a0@ | Translate nibble and write 1142 1143 /* 1144 * We enter with the last byte of the sector data lead-in 1145 * between our teeth (%D1, that is). 1146 */ 1147wsDataEntry: 1148 moveb %a3@+,%d0 | Get first byte 1149 addxb %d0,%d5 1150 eorb %d7,%d0 1151 moveb %d0,%d3 | Keep top two bits 1152 rolw #2,%d3 | by shifting them to MSByte 1153 andib #0x3F,%d1 1154wsRDY03: 1155 tstb %a2@ | IWM ready? 1156 bpl wsRDY03 1157 moveb %a4@(0,%d1),%a0@ | Translate nibble and write 1158 1159 moveb %a3@+,%d1 | Get second byte 1160 addxb %d1,%d6 1161 eorb %d5,%d1 1162 moveb %d1,%d3 | Keep top two bits 1163 rolw #2,%d3 | by shifting them to MSByte 1164 andib #0x3F,%d2 1165wsRDY04: 1166 tstb %a2@ | IWM ready? 1167 bpl wsRDY04 1168 moveb %a4@(0,%d2),%a0@ | Translate nibble and write 1169 1170 /* 1171 * XXX We have a classic off-by-one error here: the last access 1172 * reaches beyond the data buffer which bombs with memory 1173 * protection. The value read isn't used anyway... 1174 * Hopefully there is enough time for an additional check 1175 * (exit the last loop cycle before the buffer access). 1176 */ 1177 tstl %d4 | Last loop cycle? 1178 beq wsSDDone | Then get out while we can. 1179 1180 moveb %a3@+,%d2 | Get third byte 1181 tstw %d4 | First write tag buffer,... 1182 bne wsData 1183 1184 swap %d4 | ...then write data buffer 1185 bne wsSD1 1186 1187 /* 1188 * Write nibbles for last 2 bytes, then 1189 * split checksum bytes in 6&2 and write them to disk 1190 */ 1191wsSDDone: 1192 clrb %d3 | No 513th byte 1193 lsrw #6,%d3 | Set up 2 bit nibbles 1194wsRDY05: 1195 tstb %a2@ | IWM ready? 1196 bpl wsRDY05 1197 moveb %a4@(0,%d3),%a0@ | Write fragments 1198 moveb %d5,%d3 1199 rolw #2,%d3 1200 moveb %d6,%d3 1201 rolw #2,%d3 1202 andib #0x3F,%d0 1203wsRDY06: 1204 tstb %a2@ | IWM ready? 1205 bpl wsRDY06 1206 moveb %a4@(0,%d0),%a0@ | Write 511th byte 1207 andib #0x3F,%d1 1208wsRDY07: 1209 tstb %a2@ | IWM ready? 1210 bpl wsRDY07 1211 moveb %a4@(0,%d1),%a0@ | write 512th byte 1212 moveb %d7,%d3 1213 lsrw #6,%d3 | Get fragments ready 1214wsRDY08: 1215 tstb %a2@ | IWM ready? 1216 bpl wsRDY08 1217 moveb %a4@(0,%d3),%a0@ | Write fragments 1218 andib #0x3F,%d5 1219wsRDY09: 1220 tstb %a2@ | IWM ready? 1221 bpl wsRDY09 1222 moveb %a4@(0,%d5),%a0@ | Write first checksum byte 1223 andib #0x3F,%D6 1224wsRDY10: 1225 tstb %a2@ | IWM ready? 1226 bpl wsRDY10 1227 moveb %a4@(0,%d6),%a0@ | Write second checksum byte 1228 andib #0x3F,%d7 1229wsRDY11: 1230 tstb %a2@ | IWM ready? 1231 bpl wsRDY11 1232 moveb %a4@(0,%d7),%a0@ | Write third checksum byte 1233 1234 /* 1235 * Write sector data lead-out 1236 */ 1237 lea dataLeadOut,%a4 | Sector data lead-out 1238 moveq #3,%d2 | Four bytes long {3,2,1,0} 1239wsLeadOut: 1240 moveb %a2@,%d1 | IWM ready? 1241 bpl wsLeadOut 1242 moveb %a4@+,%a0@ | Write lead-out 1243 dbf %d2,wsLeadOut 1244 1245 moveq #0,%d0 1246 btst #6,%d1 | Check IWM underrun bit 1247 bne wsNoErr 1248 1249 moveq #wrUnderRun,%d0 | Could not write 1250 | fast enough to keep up with IWM 1251wsNoErr: 1252 tstb %a0@(0x0200) | q7L -- Write OFF 1253 1254wsDone: 1255 tstb %d0 | Any error? Simply retry 1256 bne wsBufInvalid 1257 1258 movel %a6@(-10),%a4 | Else, get ptr to current slot 1259 clrl %a4@(o_valid) | Mark current buffer "clean" 1260 bra wsNextSect 1261 1262wsBufInvalid: 1263 subqb #1,%a6@(-6) | retries 1264 bne wsNextSect 1265 | Sector not found, but 1266 tstb %d0 | don't set error code if we 1267 bne wsAllDone | already have one. 1268 moveq #sectNFErr,%d0 1269 1270wsAllDone: 1271 movew %a6@(-2),%sr | Restore interrupt mask 1272 moveml %sp@+,%d1-%d7/%a0-%a5 1273 unlk %a6 1274 rts 1275 1276 1277 1278/** 1279 ** Local functions 1280 **/ 1281 1282/* 1283 * iwmDelay 1284 * 1285 * In-kernel calls to delay() in mac68k/clock.c bomb 1286 * 1287 * Parameters: %d0 delay in milliseconds 1288 * Trashes: %d0, %d1 1289 * Returns: - 1290 */ 1291iwmDelay: 1292 /* TimeDBRA is ~8K for 040/33 machines, so we need nested loops */ 1293id00: movew _C_LABEL(TimeDBRA),%d1 | dbra loops per ms 1294id01: dbra %d1,id01 | 1295 dbra %d0,id00 1296 rts 1297 1298 1299/* 1300 * selDriveReg -- Select drive status/control register 1301 * 1302 * Parameters: %d0 register # 1303 * (bit 0 - CA2, bit 1 - SEL, bit 2 - CA0, bit 3 - CA1) 1304 * %a0 IWM base address 1305 * %a1 VIA base address 1306 * Returns: %d0 register # (unchanged) 1307 */ 1308selDriveReg: 1309 tstb %a0@(ph0H) | default CA0 to 1 (says IM III) 1310 tstb %a0@(ph1H) | default CA1 to 1 1311 1312 btst #0,%d0 | bit 0 set => CA2 on 1313 beq se00 1314 tstb %a0@(ph2H) 1315 bra se01 1316se00: 1317 tstb %a0@(ph2L) 1318 1319se01: 1320 btst #1,%d0 | bit 1 set => SEL on (VIA 1) 1321 beq se02 1322 bset #vHeadSel,%a1@(vBufA) 1323 bra se03 1324se02: 1325 bclr #vHeadSel,%a1@(vBufA) 1326 1327se03: 1328 btst #2,%d0 | bit 2 set => CA0 on 1329 bne se04 1330 tstb %a0@(ph0L) 1331 1332se04: 1333 btst #3,%d0 | bit 3 set => CA1 on 1334 bne se05 1335 tstb %a0@(ph1L) 1336se05: 1337 rts 1338 1339 1340 1341/* 1342 * dstatus -- check drive status (bit 7 - N flag) wrt. a previously 1343 * set status tag. 1344 * 1345 * Parameters: %d0 register selector 1346 * %a0 IWM base address 1347 * Returns: %d0 status 1348 */ 1349dstatus: 1350 tstb %a0@(q6H) 1351 moveb %a0@(q7L),%d0 1352 tstb %a0@(q6L) | leave in "read data reg" 1353 tstb %d0 | state for safety 1354 rts 1355 1356 1357/* 1358 * driveStat -- query drive status. 1359 * 1360 * Parameters: %a0 IWMBase 1361 * %a1 VIABase 1362 * %d0 register selector 1363 * Returns: %d0 status (Bit 7) 1364 */ 1365driveStat: 1366 tstb %a0@(mtrOn) | ENABLE; turn drive on 1367 bsr selDriveReg 1368 bsr dstatus 1369 rts 1370 1371 1372/* 1373 * dtrigger -- toggle LSTRB line to give drive a strobe signal 1374 * IM III says pulse length = 1 us < t < 1 ms 1375 * 1376 * Parameters: %a0 IWMBase 1377 * %a1 VIABase 1378 * Returns: - 1379 */ 1380dtrigger: 1381 tstb %a0@(ph3H) | LSTRB high 1382 moveb %a1@(vBufA),%a1@(vBufA) | intelligent nop seen in q700 ROM 1383 tstb %a0@(ph3L) | LSTRB low 1384 rts 1385 1386 1387/* 1388 * driveCmd -- send command to drive. 1389 * 1390 * Parameters: %a0 IWMBase 1391 * %a1 VIABase 1392 * %d0 Command token 1393 * Returns: - 1394 */ 1395driveCmd: 1396 bsr selDriveReg 1397 bsr dtrigger 1398 rts 1399 1400 1401/* 1402 * readSectHdr -- read and decode the next available sector header. 1403 * 1404 * TODO: Poll SCC as long as interrupts are disabled. 1405 * 1406 * Parameters: %a4 sectorHdr_t address 1407 * Returns: %d0 result code 1408 * Uses: %d0-%d4, %a0, %a2-%a4 1409 */ 1410readSectHdr: 1411 moveq #3,%d4 | Read 3 chars from IWM for sync 1412 movew #600,%d3 | Retries to sync to disk 1413 moveq #0,%d2 | Clear scratch regs 1414 moveq #0,%d1 1415 moveq #0,%d0 1416 movel _C_LABEL(IWMBase),%a0 | IWM base address 1417 1418 tstb %a0@(q7L) 1419 lea %a0@(q6L),%a0 | IWM data register 1420shReadSy: 1421 moveb %a0@,%d2 | Read char 1422 dbra %d3,shSeekSync 1423 1424 moveq #noNybErr,%d0 | Disk is blank? 1425 bra shDone 1426 1427shSeekSync: 1428 bpl shReadSy | No char at IWM, repeat read 1429 subqw #1,%d4 1430 bne shReadSy 1431 /* 1432 * When we get here, the IWM should be in sync with the data 1433 * stream from disk. 1434 * Next look for sector header lead-in 'D5 AA 96' 1435 */ 1436 movew #1500,%d3 | Retries to seek header 1437shLeadIn: 1438 lea hdrLeadIn,%a3 | Sector header lead-in bytes 1439 moveq #0x03,%d4 | is 3 bytes long 1440shLI1: 1441 moveb %a0@,%d2 | Get next byte 1442 bpl shLI1 | No char at IWM, repeat read 1443 dbra %d3,shLI2 1444 moveq #noAdrMkErr,%d0 | Can't find an address mark 1445 bra shDone 1446 1447shLI2: 1448 cmpb %a3@+,%d2 1449 bne shLeadIn | If ne restart scan 1450 subqw #1,%d4 1451 bne shLI1 1452 /* 1453 * We have found the lead-in. Now get the header information. 1454 * Reg %d4 holds the checksum. 1455 */ 1456 lea diskTo-0x90,%a2 | Translate disk bytes -> 6&2 1457shHdr1: 1458 moveb %a0@,%d0 | Get 1st char 1459 bpl shHdr1 1460 moveb %a2@(0,%d0),%d1 | and remap it 1461 moveb %d1,%d4 1462 rorw #6,%d1 | separate 2:6, drop hi bits 1463shHdr2: 1464 moveb %a0@,%d0 | Get 2nd char 1465 bpl shHdr2 1466 moveb %a2@(0,%d0),%d2 | and remap it 1467 eorb %d2,%d4 1468shHdr3: 1469 moveb %a0@,%d0 | Get 3rd char 1470 bpl shHdr3 1471 moveb %a2@(0,%d0),%d1 | and remap it 1472 eorb %d1,%d4 1473 rolw #6,%d1 | 1474shHdr4: 1475 moveb %a0@,%d0 | Get 4th char 1476 bpl shHdr4 1477 moveb %a2@(0,%d0),%d3 | and remap it 1478 eorb %d3,%d4 1479shHdr5: 1480 moveb %a0@,%d0 | Get checksum byte 1481 bpl shHdr5 1482 moveb %a2@(0,%d0),%d5 | and remap it 1483 eorb %d5,%d4 1484 bne shCsErr | Checksum ok? 1485 /* 1486 * We now have in 1487 * %d1/lsb track number 1488 * %d1/msb bit 3 is side bit 1489 * %d2 sector number 1490 * %d3 ??? 1491 * %d5 checksum (=0) 1492 * 1493 * Next check for lead-out. 1494 */ 1495 moveq #1,%d4 | is 2 bytes long 1496shHdr6: 1497 moveb %a0@,%d0 | Get token 1498 bpl shHdr6 1499 cmpb %a3@+,%d0 | Check 1500 bne shLOErr | Fault! 1501 dbra %d4,shHdr6 1502 movew %d1,%d0 | Isolate side bit 1503 lsrw #8,%d0 1504 moveb %d0,%a4@+ | and store it 1505 moveb %d1,%a4@+ | Store track number 1506 moveb %d2,%a4@+ | and sector number 1507 moveq #0,%d0 | All is well 1508 bra shDone 1509 1510shCsErr: 1511 moveq #badCkSmErr,%d0 | Bad sector header checksum 1512 bra shDone 1513shLOErr: 1514 moveq #badBtSlpErr,%d0 | Bad address mark (no lead-out) 1515 1516shDone: 1517 tstl %d0 | Set flags 1518 rts 1519