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