| /* SPDX-License-Identifier: GPL-2.0-or-later */ |
| /* |
| * low-level functions for the SWIM floppy controller |
| * |
| * needs assembly language because is very timing dependent |
| * this controller exists only on macintosh 680x0 based |
| * |
| * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info> |
| * |
| * based on Alastair Bridgewater SWIM analysis, 2001 |
| * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath. |
| * |
| * 2004-08-21 (lv) - Initial implementation |
| * 2008-11-05 (lv) - add get_swim_mode |
| */ |
| |
| .equ write_data, 0x0000 |
| .equ write_mark, 0x0200 |
| .equ write_CRC, 0x0400 |
| .equ write_parameter,0x0600 |
| .equ write_phase, 0x0800 |
| .equ write_setup, 0x0a00 |
| .equ write_mode0, 0x0c00 |
| .equ write_mode1, 0x0e00 |
| .equ read_data, 0x1000 |
| .equ read_mark, 0x1200 |
| .equ read_error, 0x1400 |
| .equ read_parameter, 0x1600 |
| .equ read_phase, 0x1800 |
| .equ read_setup, 0x1a00 |
| .equ read_status, 0x1c00 |
| .equ read_handshake, 0x1e00 |
| |
| .equ o_side, 0 |
| .equ o_track, 1 |
| .equ o_sector, 2 |
| .equ o_size, 3 |
| .equ o_crc0, 4 |
| .equ o_crc1, 5 |
| |
| .equ seek_time, 30000 |
| .equ max_retry, 40 |
| .equ sector_size, 512 |
| |
| .global swim_read_sector_header |
| swim_read_sector_header: |
| link %a6, #0 |
| moveml %d1-%d5/%a0-%a4,%sp@- |
| movel %a6@(0x0c), %a4 |
| bsr mfm_read_addrmark |
| moveml %sp@+, %d1-%d5/%a0-%a4 |
| unlk %a6 |
| rts |
| |
| sector_address_mark: |
| .byte 0xa1, 0xa1, 0xa1, 0xfe |
| sector_data_mark: |
| .byte 0xa1, 0xa1, 0xa1, 0xfb |
| |
| mfm_read_addrmark: |
| movel %a6@(0x08), %a3 |
| lea %a3@(read_handshake), %a2 |
| lea %a3@(read_mark), %a3 |
| moveq #-1, %d0 |
| movew #seek_time, %d2 |
| |
| wait_header_init: |
| tstb %a3@(read_error - read_mark) |
| moveb #0x18, %a3@(write_mode0 - read_mark) |
| moveb #0x01, %a3@(write_mode1 - read_mark) |
| moveb #0x01, %a3@(write_mode0 - read_mark) |
| tstb %a3@(read_error - read_mark) |
| moveb #0x08, %a3@(write_mode1 - read_mark) |
| |
| lea sector_address_mark, %a0 |
| moveq #3, %d1 |
| |
| wait_addr_mark_byte: |
| |
| tstb %a2@ |
| dbmi %d2, wait_addr_mark_byte |
| bpl header_exit |
| |
| moveb %a3@, %d3 |
| cmpb %a0@+, %d3 |
| dbne %d1, wait_addr_mark_byte |
| bne wait_header_init |
| |
| moveq #max_retry, %d2 |
| |
| amark0: tstb %a2@ |
| dbmi %d2, amark0 |
| bpl signal_nonyb |
| |
| moveb %a3@, %a4@(o_track) |
| |
| moveq #max_retry, %d2 |
| |
| amark1: tstb %a2@ |
| dbmi %d2, amark1 |
| bpl signal_nonyb |
| |
| moveb %a3@, %a4@(o_side) |
| |
| moveq #max_retry, %d2 |
| |
| amark2: tstb %a2@ |
| dbmi %d2, amark2 |
| bpl signal_nonyb |
| |
| moveb %a3@, %a4@(o_sector) |
| |
| moveq #max_retry, %d2 |
| |
| amark3: tstb %a2@ |
| dbmi %d2, amark3 |
| bpl signal_nonyb |
| |
| moveb %a3@, %a4@(o_size) |
| |
| moveq #max_retry, %d2 |
| |
| crc0: tstb %a2@ |
| dbmi %d2, crc0 |
| bpl signal_nonyb |
| |
| moveb %a3@, %a4@(o_crc0) |
| |
| moveq #max_retry, %d2 |
| |
| crc1: tstb %a2@ |
| dbmi %d2, crc1 |
| bpl signal_nonyb |
| |
| moveb %a3@, %a4@(o_crc1) |
| |
| tstb %a3@(read_error - read_mark) |
| |
| header_exit: |
| moveq #0, %d0 |
| moveb #0x18, %a3@(write_mode0 - read_mark) |
| rts |
| signal_nonyb: |
| moveq #-1, %d0 |
| moveb #0x18, %a3@(write_mode0 - read_mark) |
| rts |
| |
| .global swim_read_sector_data |
| swim_read_sector_data: |
| link %a6, #0 |
| moveml %d1-%d5/%a0-%a5,%sp@- |
| movel %a6@(0x0c), %a4 |
| bsr mfm_read_data |
| moveml %sp@+, %d1-%d5/%a0-%a5 |
| unlk %a6 |
| rts |
| |
| mfm_read_data: |
| movel %a6@(0x08), %a3 |
| lea %a3@(read_handshake), %a2 |
| lea %a3@(read_data), %a5 |
| lea %a3@(read_mark), %a3 |
| movew #seek_time, %d2 |
| |
| wait_data_init: |
| tstb %a3@(read_error - read_mark) |
| moveb #0x18, %a3@(write_mode0 - read_mark) |
| moveb #0x01, %a3@(write_mode1 - read_mark) |
| moveb #0x01, %a3@(write_mode0 - read_mark) |
| tstb %a3@(read_error - read_mark) |
| moveb #0x08, %a3@(write_mode1 - read_mark) |
| |
| lea sector_data_mark, %a0 |
| moveq #3, %d1 |
| |
| /* wait data address mark */ |
| |
| wait_data_mark_byte: |
| |
| tstb %a2@ |
| dbmi %d2, wait_data_mark_byte |
| bpl data_exit |
| |
| moveb %a3@, %d3 |
| cmpb %a0@+, %d3 |
| dbne %d1, wait_data_mark_byte |
| bne wait_data_init |
| |
| /* read data */ |
| |
| tstb %a3@(read_error - read_mark) |
| |
| movel #sector_size-1, %d4 /* sector size */ |
| read_new_data: |
| movew #max_retry, %d2 |
| read_data_loop: |
| moveb %a2@, %d5 |
| andb #0xc0, %d5 |
| dbne %d2, read_data_loop |
| beq data_exit |
| moveb %a5@, %a4@+ |
| andb #0x40, %d5 |
| dbne %d4, read_new_data |
| beq exit_loop |
| moveb %a5@, %a4@+ |
| dbra %d4, read_new_data |
| exit_loop: |
| |
| /* read CRC */ |
| |
| movew #max_retry, %d2 |
| data_crc0: |
| |
| tstb %a2@ |
| dbmi %d2, data_crc0 |
| bpl data_exit |
| |
| moveb %a3@, %d5 |
| |
| moveq #max_retry, %d2 |
| |
| data_crc1: |
| |
| tstb %a2@ |
| dbmi %d2, data_crc1 |
| bpl data_exit |
| |
| moveb %a3@, %d5 |
| |
| tstb %a3@(read_error - read_mark) |
| |
| moveb #0x18, %a3@(write_mode0 - read_mark) |
| |
| /* return number of bytes read */ |
| |
| movel #sector_size, %d0 |
| addw #1, %d4 |
| subl %d4, %d0 |
| rts |
| data_exit: |
| moveb #0x18, %a3@(write_mode0 - read_mark) |
| moveq #-1, %d0 |
| rts |