/* 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