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