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