1*8852ecd9SLaurent Vivier/* 2*8852ecd9SLaurent Vivier * low-level functions for the SWIM floppy controller 3*8852ecd9SLaurent Vivier * 4*8852ecd9SLaurent Vivier * needs assembly language because is very timing dependent 5*8852ecd9SLaurent Vivier * this controller exists only on macintosh 680x0 based 6*8852ecd9SLaurent Vivier * 7*8852ecd9SLaurent Vivier * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info> 8*8852ecd9SLaurent Vivier * 9*8852ecd9SLaurent Vivier * based on Alastair Bridgewater SWIM analysis, 2001 10*8852ecd9SLaurent Vivier * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath. 11*8852ecd9SLaurent Vivier * 12*8852ecd9SLaurent Vivier * This program is free software; you can redistribute it and/or 13*8852ecd9SLaurent Vivier * modify it under the terms of the GNU General Public License 14*8852ecd9SLaurent Vivier * as published by the Free Software Foundation; either version 15*8852ecd9SLaurent Vivier * 2 of the License, or (at your option) any later version. 16*8852ecd9SLaurent Vivier * 17*8852ecd9SLaurent Vivier * 2004-08-21 (lv) - Initial implementation 18*8852ecd9SLaurent Vivier * 2008-11-05 (lv) - add get_swim_mode 19*8852ecd9SLaurent Vivier */ 20*8852ecd9SLaurent Vivier 21*8852ecd9SLaurent Vivier .equ write_data, 0x0000 22*8852ecd9SLaurent Vivier .equ write_mark, 0x0200 23*8852ecd9SLaurent Vivier .equ write_CRC, 0x0400 24*8852ecd9SLaurent Vivier .equ write_parameter,0x0600 25*8852ecd9SLaurent Vivier .equ write_phase, 0x0800 26*8852ecd9SLaurent Vivier .equ write_setup, 0x0a00 27*8852ecd9SLaurent Vivier .equ write_mode0, 0x0c00 28*8852ecd9SLaurent Vivier .equ write_mode1, 0x0e00 29*8852ecd9SLaurent Vivier .equ read_data, 0x1000 30*8852ecd9SLaurent Vivier .equ read_mark, 0x1200 31*8852ecd9SLaurent Vivier .equ read_error, 0x1400 32*8852ecd9SLaurent Vivier .equ read_parameter, 0x1600 33*8852ecd9SLaurent Vivier .equ read_phase, 0x1800 34*8852ecd9SLaurent Vivier .equ read_setup, 0x1a00 35*8852ecd9SLaurent Vivier .equ read_status, 0x1c00 36*8852ecd9SLaurent Vivier .equ read_handshake, 0x1e00 37*8852ecd9SLaurent Vivier 38*8852ecd9SLaurent Vivier .equ o_side, 0 39*8852ecd9SLaurent Vivier .equ o_track, 1 40*8852ecd9SLaurent Vivier .equ o_sector, 2 41*8852ecd9SLaurent Vivier .equ o_size, 3 42*8852ecd9SLaurent Vivier .equ o_crc0, 4 43*8852ecd9SLaurent Vivier .equ o_crc1, 5 44*8852ecd9SLaurent Vivier 45*8852ecd9SLaurent Vivier .equ seek_time, 30000 46*8852ecd9SLaurent Vivier .equ max_retry, 40 47*8852ecd9SLaurent Vivier .equ sector_size, 512 48*8852ecd9SLaurent Vivier 49*8852ecd9SLaurent Vivier .global swim_read_sector_header 50*8852ecd9SLaurent Vivierswim_read_sector_header: 51*8852ecd9SLaurent Vivier link %a6, #0 52*8852ecd9SLaurent Vivier moveml %d1-%d5/%a0-%a4,%sp@- 53*8852ecd9SLaurent Vivier movel %a6@(0x0c), %a4 54*8852ecd9SLaurent Vivier bsr mfm_read_addrmark 55*8852ecd9SLaurent Vivier moveml %sp@+, %d1-%d5/%a0-%a4 56*8852ecd9SLaurent Vivier unlk %a6 57*8852ecd9SLaurent Vivier rts 58*8852ecd9SLaurent Vivier 59*8852ecd9SLaurent Viviersector_address_mark: 60*8852ecd9SLaurent Vivier .byte 0xa1, 0xa1, 0xa1, 0xfe 61*8852ecd9SLaurent Viviersector_data_mark: 62*8852ecd9SLaurent Vivier .byte 0xa1, 0xa1, 0xa1, 0xfb 63*8852ecd9SLaurent Vivier 64*8852ecd9SLaurent Viviermfm_read_addrmark: 65*8852ecd9SLaurent Vivier movel %a6@(0x08), %a3 66*8852ecd9SLaurent Vivier lea %a3@(read_handshake), %a2 67*8852ecd9SLaurent Vivier lea %a3@(read_mark), %a3 68*8852ecd9SLaurent Vivier moveq #-1, %d0 69*8852ecd9SLaurent Vivier movew #seek_time, %d2 70*8852ecd9SLaurent Vivier 71*8852ecd9SLaurent Vivierwait_header_init: 72*8852ecd9SLaurent Vivier tstb %a3@(read_error - read_mark) 73*8852ecd9SLaurent Vivier moveb #0x18, %a3@(write_mode0 - read_mark) 74*8852ecd9SLaurent Vivier moveb #0x01, %a3@(write_mode1 - read_mark) 75*8852ecd9SLaurent Vivier moveb #0x01, %a3@(write_mode0 - read_mark) 76*8852ecd9SLaurent Vivier tstb %a3@(read_error - read_mark) 77*8852ecd9SLaurent Vivier moveb #0x08, %a3@(write_mode1 - read_mark) 78*8852ecd9SLaurent Vivier 79*8852ecd9SLaurent Vivier lea sector_address_mark, %a0 80*8852ecd9SLaurent Vivier moveq #3, %d1 81*8852ecd9SLaurent Vivier 82*8852ecd9SLaurent Vivierwait_addr_mark_byte: 83*8852ecd9SLaurent Vivier 84*8852ecd9SLaurent Vivier tstb %a2@ 85*8852ecd9SLaurent Vivier dbmi %d2, wait_addr_mark_byte 86*8852ecd9SLaurent Vivier bpl header_exit 87*8852ecd9SLaurent Vivier 88*8852ecd9SLaurent Vivier moveb %a3@, %d3 89*8852ecd9SLaurent Vivier cmpb %a0@+, %d3 90*8852ecd9SLaurent Vivier dbne %d1, wait_addr_mark_byte 91*8852ecd9SLaurent Vivier bne wait_header_init 92*8852ecd9SLaurent Vivier 93*8852ecd9SLaurent Vivier moveq #max_retry, %d2 94*8852ecd9SLaurent Vivier 95*8852ecd9SLaurent Vivieramark0: tstb %a2@ 96*8852ecd9SLaurent Vivier dbmi %d2, amark0 97*8852ecd9SLaurent Vivier bpl signal_nonyb 98*8852ecd9SLaurent Vivier 99*8852ecd9SLaurent Vivier moveb %a3@, %a4@(o_track) 100*8852ecd9SLaurent Vivier 101*8852ecd9SLaurent Vivier moveq #max_retry, %d2 102*8852ecd9SLaurent Vivier 103*8852ecd9SLaurent Vivieramark1: tstb %a2@ 104*8852ecd9SLaurent Vivier dbmi %d2, amark1 105*8852ecd9SLaurent Vivier bpl signal_nonyb 106*8852ecd9SLaurent Vivier 107*8852ecd9SLaurent Vivier moveb %a3@, %a4@(o_side) 108*8852ecd9SLaurent Vivier 109*8852ecd9SLaurent Vivier moveq #max_retry, %d2 110*8852ecd9SLaurent Vivier 111*8852ecd9SLaurent Vivieramark2: tstb %a2@ 112*8852ecd9SLaurent Vivier dbmi %d2, amark2 113*8852ecd9SLaurent Vivier bpl signal_nonyb 114*8852ecd9SLaurent Vivier 115*8852ecd9SLaurent Vivier moveb %a3@, %a4@(o_sector) 116*8852ecd9SLaurent Vivier 117*8852ecd9SLaurent Vivier moveq #max_retry, %d2 118*8852ecd9SLaurent Vivier 119*8852ecd9SLaurent Vivieramark3: tstb %a2@ 120*8852ecd9SLaurent Vivier dbmi %d2, amark3 121*8852ecd9SLaurent Vivier bpl signal_nonyb 122*8852ecd9SLaurent Vivier 123*8852ecd9SLaurent Vivier moveb %a3@, %a4@(o_size) 124*8852ecd9SLaurent Vivier 125*8852ecd9SLaurent Vivier moveq #max_retry, %d2 126*8852ecd9SLaurent Vivier 127*8852ecd9SLaurent Viviercrc0: tstb %a2@ 128*8852ecd9SLaurent Vivier dbmi %d2, crc0 129*8852ecd9SLaurent Vivier bpl signal_nonyb 130*8852ecd9SLaurent Vivier 131*8852ecd9SLaurent Vivier moveb %a3@, %a4@(o_crc0) 132*8852ecd9SLaurent Vivier 133*8852ecd9SLaurent Vivier moveq #max_retry, %d2 134*8852ecd9SLaurent Vivier 135*8852ecd9SLaurent Viviercrc1: tstb %a2@ 136*8852ecd9SLaurent Vivier dbmi %d2, crc1 137*8852ecd9SLaurent Vivier bpl signal_nonyb 138*8852ecd9SLaurent Vivier 139*8852ecd9SLaurent Vivier moveb %a3@, %a4@(o_crc1) 140*8852ecd9SLaurent Vivier 141*8852ecd9SLaurent Vivier tstb %a3@(read_error - read_mark) 142*8852ecd9SLaurent Vivier 143*8852ecd9SLaurent Vivierheader_exit: 144*8852ecd9SLaurent Vivier moveq #0, %d0 145*8852ecd9SLaurent Vivier moveb #0x18, %a3@(write_mode0 - read_mark) 146*8852ecd9SLaurent Vivier rts 147*8852ecd9SLaurent Viviersignal_nonyb: 148*8852ecd9SLaurent Vivier moveq #-1, %d0 149*8852ecd9SLaurent Vivier moveb #0x18, %a3@(write_mode0 - read_mark) 150*8852ecd9SLaurent Vivier rts 151*8852ecd9SLaurent Vivier 152*8852ecd9SLaurent Vivier .global swim_read_sector_data 153*8852ecd9SLaurent Vivierswim_read_sector_data: 154*8852ecd9SLaurent Vivier link %a6, #0 155*8852ecd9SLaurent Vivier moveml %d1-%d5/%a0-%a5,%sp@- 156*8852ecd9SLaurent Vivier movel %a6@(0x0c), %a4 157*8852ecd9SLaurent Vivier bsr mfm_read_data 158*8852ecd9SLaurent Vivier moveml %sp@+, %d1-%d5/%a0-%a5 159*8852ecd9SLaurent Vivier unlk %a6 160*8852ecd9SLaurent Vivier rts 161*8852ecd9SLaurent Vivier 162*8852ecd9SLaurent Viviermfm_read_data: 163*8852ecd9SLaurent Vivier movel %a6@(0x08), %a3 164*8852ecd9SLaurent Vivier lea %a3@(read_handshake), %a2 165*8852ecd9SLaurent Vivier lea %a3@(read_data), %a5 166*8852ecd9SLaurent Vivier lea %a3@(read_mark), %a3 167*8852ecd9SLaurent Vivier movew #seek_time, %d2 168*8852ecd9SLaurent Vivier 169*8852ecd9SLaurent Vivierwait_data_init: 170*8852ecd9SLaurent Vivier tstb %a3@(read_error - read_mark) 171*8852ecd9SLaurent Vivier moveb #0x18, %a3@(write_mode0 - read_mark) 172*8852ecd9SLaurent Vivier moveb #0x01, %a3@(write_mode1 - read_mark) 173*8852ecd9SLaurent Vivier moveb #0x01, %a3@(write_mode0 - read_mark) 174*8852ecd9SLaurent Vivier tstb %a3@(read_error - read_mark) 175*8852ecd9SLaurent Vivier moveb #0x08, %a3@(write_mode1 - read_mark) 176*8852ecd9SLaurent Vivier 177*8852ecd9SLaurent Vivier lea sector_data_mark, %a0 178*8852ecd9SLaurent Vivier moveq #3, %d1 179*8852ecd9SLaurent Vivier 180*8852ecd9SLaurent Vivier /* wait data address mark */ 181*8852ecd9SLaurent Vivier 182*8852ecd9SLaurent Vivierwait_data_mark_byte: 183*8852ecd9SLaurent Vivier 184*8852ecd9SLaurent Vivier tstb %a2@ 185*8852ecd9SLaurent Vivier dbmi %d2, wait_data_mark_byte 186*8852ecd9SLaurent Vivier bpl data_exit 187*8852ecd9SLaurent Vivier 188*8852ecd9SLaurent Vivier moveb %a3@, %d3 189*8852ecd9SLaurent Vivier cmpb %a0@+, %d3 190*8852ecd9SLaurent Vivier dbne %d1, wait_data_mark_byte 191*8852ecd9SLaurent Vivier bne wait_data_init 192*8852ecd9SLaurent Vivier 193*8852ecd9SLaurent Vivier /* read data */ 194*8852ecd9SLaurent Vivier 195*8852ecd9SLaurent Vivier tstb %a3@(read_error - read_mark) 196*8852ecd9SLaurent Vivier 197*8852ecd9SLaurent Vivier movel #sector_size-1, %d4 /* sector size */ 198*8852ecd9SLaurent Vivierread_new_data: 199*8852ecd9SLaurent Vivier movew #max_retry, %d2 200*8852ecd9SLaurent Vivierread_data_loop: 201*8852ecd9SLaurent Vivier moveb %a2@, %d5 202*8852ecd9SLaurent Vivier andb #0xc0, %d5 203*8852ecd9SLaurent Vivier dbne %d2, read_data_loop 204*8852ecd9SLaurent Vivier beq data_exit 205*8852ecd9SLaurent Vivier moveb %a5@, %a4@+ 206*8852ecd9SLaurent Vivier andb #0x40, %d5 207*8852ecd9SLaurent Vivier dbne %d4, read_new_data 208*8852ecd9SLaurent Vivier beq exit_loop 209*8852ecd9SLaurent Vivier moveb %a5@, %a4@+ 210*8852ecd9SLaurent Vivier dbra %d4, read_new_data 211*8852ecd9SLaurent Vivierexit_loop: 212*8852ecd9SLaurent Vivier 213*8852ecd9SLaurent Vivier /* read CRC */ 214*8852ecd9SLaurent Vivier 215*8852ecd9SLaurent Vivier movew #max_retry, %d2 216*8852ecd9SLaurent Vivierdata_crc0: 217*8852ecd9SLaurent Vivier 218*8852ecd9SLaurent Vivier tstb %a2@ 219*8852ecd9SLaurent Vivier dbmi %d2, data_crc0 220*8852ecd9SLaurent Vivier bpl data_exit 221*8852ecd9SLaurent Vivier 222*8852ecd9SLaurent Vivier moveb %a3@, %d5 223*8852ecd9SLaurent Vivier 224*8852ecd9SLaurent Vivier moveq #max_retry, %d2 225*8852ecd9SLaurent Vivier 226*8852ecd9SLaurent Vivierdata_crc1: 227*8852ecd9SLaurent Vivier 228*8852ecd9SLaurent Vivier tstb %a2@ 229*8852ecd9SLaurent Vivier dbmi %d2, data_crc1 230*8852ecd9SLaurent Vivier bpl data_exit 231*8852ecd9SLaurent Vivier 232*8852ecd9SLaurent Vivier moveb %a3@, %d5 233*8852ecd9SLaurent Vivier 234*8852ecd9SLaurent Vivier tstb %a3@(read_error - read_mark) 235*8852ecd9SLaurent Vivier 236*8852ecd9SLaurent Vivier moveb #0x18, %a3@(write_mode0 - read_mark) 237*8852ecd9SLaurent Vivier 238*8852ecd9SLaurent Vivier /* return number of bytes read */ 239*8852ecd9SLaurent Vivier 240*8852ecd9SLaurent Vivier movel #sector_size, %d0 241*8852ecd9SLaurent Vivier addw #1, %d4 242*8852ecd9SLaurent Vivier subl %d4, %d0 243*8852ecd9SLaurent Vivier rts 244*8852ecd9SLaurent Vivierdata_exit: 245*8852ecd9SLaurent Vivier moveb #0x18, %a3@(write_mode0 - read_mark) 246*8852ecd9SLaurent Vivier moveq #-1, %d0 247*8852ecd9SLaurent Vivier rts 248