iwm.s revision 1.3 1 1.3 chs /* $NetBSD: iwm.s,v 1.3 2001/11/20 03:19:44 chs Exp $ */
2 1.1 scottr
3 1.1 scottr /*
4 1.2 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.2 scottr * o We run at spl4 to give the NMI switch a chance. All currently
50 1.2 scottr * supported machines have no interrupt sources > 4 (SSC) -- the
51 1.2 scottr * Q700 interrupt levels can be shifted around in A/UX mode,
52 1.2 scottr * but we're not there, yet.
53 1.2 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.2 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.3 chs .extern _C_LABEL(TimeDBRA) | in mac68k/macrom.c
77 1.3 chs .extern _C_LABEL(Via1Base) | in mac68k/machdep.c
78 1.3 chs .extern _C_LABEL(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.3 chs * %a0 IWM base address
149 1.3 chs * %a1 VIA1 base address
150 1.1 scottr *
151 1.3 chs * %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.3 chs * Returns: %d0 flag
170 1.1 scottr */
171 1.1 scottr ENTRY(iwmQueryDrvFlag)
172 1.3 chs link %a6,#0
173 1.3 chs moveml %d1/%a0-%a1,%sp@-
174 1.3 chs movel _C_LABEL(IWMBase),%a0
175 1.3 chs movel _C_LABEL(Via1Base),%a1
176 1.1 scottr
177 1.3 chs movel %a6@(8),%d0 | Get drive #
178 1.1 scottr beq quDrv00
179 1.3 chs 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.3 chs tstb %a0@(intDrive) | SELECT; choose drive #0
186 1.1 scottr bra queryDrv
187 1.1 scottr
188 1.1 scottr quDrv01:
189 1.3 chs tstb %a0@(extDrive) | SELECT; choose drive #1
190 1.1 scottr
191 1.1 scottr queryDrv:
192 1.3 chs movel %a6@(12),%d0 | Get register #
193 1.1 scottr bsr driveStat
194 1.1 scottr
195 1.1 scottr quDone:
196 1.3 chs moveml %sp@+,%d1/%a0-%a1
197 1.3 chs 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.3 chs * Returns: %d0 result code
209 1.1 scottr */
210 1.1 scottr ENTRY(iwmReadSectHdr)
211 1.3 chs link %a6,#0
212 1.3 chs moveml %d1-%d5/%a0-%a4,%sp@-
213 1.3 chs movel %a6@(0x08),%a4 | Get param block address
214 1.1 scottr bsr readSectHdr
215 1.3 chs moveml %sp@+,%d1-%d5/%a0-%a4
216 1.3 chs 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.3 chs * Returns: %d0 result code
230 1.1 scottr */
231 1.1 scottr ENTRY(iwmInit)
232 1.3 chs link %a6,#0
233 1.3 chs moveml %d2/%a0,%sp@-
234 1.3 chs movel _C_LABEL(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.3 chs tstb %a0@(ph0L) | CA0
240 1.3 chs tstb %a0@(ph1L) | CA1
241 1.3 chs tstb %a0@(ph2L) | CA2
242 1.3 chs tstb %a0@(ph3L) | LSTRB
243 1.3 chs
244 1.3 chs tstb %a0@(mtrOff) | ENABLE; make sure drive is off
245 1.3 chs tstb %a0@(intDrive) | SELECT; choose drive 1
246 1.3 chs 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.3 chs tstb %a0@(q6H)
252 1.3 chs andb %a0@(q7L),%d0 | status register
253 1.3 chs tstb %a0@(q6L)
254 1.3 chs 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.3 chs movel #0x00080000,%d2 | ca. 500,000 retries = 1.5 sec
262 1.1 scottr initLp:
263 1.3 chs moveq #initIWMErr,%d0 | Initialization error
264 1.3 chs subql #1,%d2
265 1.1 scottr bmi initErr
266 1.3 chs tstb %a0@(mtrOff) | disable drive
267 1.3 chs tstb %a0@(q6H)
268 1.3 chs moveq #0x3F,%d0
269 1.3 chs andb %a0@(q7L),%d0
270 1.3 chs 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.3 chs cmpib #iwmMode,%d0
274 1.1 scottr beq initDone
275 1.3 chs moveb #iwmMode,%a0@(q7H) | Init IWM
276 1.3 chs tstb %a0@(q7L)
277 1.1 scottr bra initLp
278 1.1 scottr
279 1.1 scottr initDone:
280 1.3 chs tstb %a0@(q6L) | Prepare IWM for data
281 1.3 chs moveq #0,%d0 | noErr
282 1.1 scottr
283 1.1 scottr initErr:
284 1.3 chs moveml %sp@+,%d2/%a0
285 1.3 chs 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.3 chs * 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.3 chs link %a6,#0
303 1.3 chs moveml %d1/%a0-%a1,%sp@-
304 1.3 chs movel _C_LABEL(IWMBase),%a0
305 1.3 chs movel _C_LABEL(Via1Base),%a1
306 1.1 scottr
307 1.3 chs moveq #-1,%d1 | no drive
308 1.1 scottr
309 1.3 chs movel %a6@(0x08),%d0 | check drive #
310 1.1 scottr beq chkDrv00
311 1.3 chs 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.3 chs tstb %a0@(intDrive) | SELECT; choose drive #0
318 1.1 scottr bra chkDrive
319 1.1 scottr
320 1.1 scottr chkDrv01:
321 1.3 chs tstb %a0@(extDrive) | SELECT; choose drive #1
322 1.1 scottr
323 1.1 scottr chkDrive:
324 1.3 chs moveq #-2,%d1 | error code
325 1.3 chs 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.3 chs moveq #0,%d1 | Drive found
330 1.3 chs tstb %a0@(mtrOn) | ENABLE; activate drive
331 1.3 chs 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.3 chs bset #0,%d1 | 1 = no.
342 1.1 scottr chkHasDisk:
343 1.3 chs moveq #diskInserted,%d0 | Disk inserted?
344 1.1 scottr bsr driveStat
345 1.1 scottr bpl chkMotorOn
346 1.3 chs bset #1,%d1 | 1 = No.
347 1.1 scottr bra chkDone
348 1.1 scottr chkMotorOn:
349 1.3 chs moveq #drvMotorState,%d0 | Motor is running?
350 1.1 scottr bsr driveStat
351 1.1 scottr bpl chkWrtProt
352 1.3 chs bset #2,%d1 | 1 = No.
353 1.1 scottr chkWrtProt:
354 1.3 chs moveq #writeProtected,%d0 | Disk is write protected?
355 1.1 scottr bsr driveStat
356 1.1 scottr bpl chkDD_HD
357 1.3 chs bset #3,%d1 | 1 = No.
358 1.1 scottr chkDD_HD:
359 1.3 chs moveq #diskIsHD,%d0 | Disk is HD? (was "drive installed")
360 1.1 scottr bsr driveStat
361 1.1 scottr bpl chkDone
362 1.3 chs bset #4,%d1 | 1 = No.
363 1.1 scottr chkDone:
364 1.3 chs movel %d1,%d0
365 1.3 chs moveml %sp@+,%d1/%a0-%a1
366 1.3 chs 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.3 chs * %a0 IWMBase
378 1.3 chs * %a1 VIABase
379 1.3 chs * Returns: %d0 result code
380 1.1 scottr */
381 1.1 scottr ENTRY(iwmDiskEject)
382 1.3 chs link %a6,#0
383 1.3 chs movel _C_LABEL(IWMBase),%a0
384 1.3 chs movel _C_LABEL(Via1Base),%a1
385 1.1 scottr
386 1.3 chs movel %a6@(0x08),%d0 | Get drive #
387 1.1 scottr beq ejDrv00
388 1.3 chs 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.3 chs tstb %a0@(intDrive) | SELECT; choose drive #0
395 1.1 scottr bra ejDisk
396 1.1 scottr
397 1.1 scottr ejDrv01:
398 1.3 chs tstb %a0@(extDrive) | SELECT; choose drive #1
399 1.1 scottr ejDisk:
400 1.3 chs tstb %a0@(mtrOn) | ENABLE; activate drive
401 1.1 scottr
402 1.3 chs moveq #motorOffCmd,%d0 | Motor off
403 1.1 scottr bsr driveCmd
404 1.1 scottr
405 1.3 chs moveq #diskInserted,%d0 | Disk inserted?
406 1.1 scottr bsr driveStat
407 1.1 scottr bmi ejDone
408 1.1 scottr
409 1.3 chs moveq #ejectDiskCmd,%d0 | Eject it
410 1.1 scottr bsr selDriveReg
411 1.1 scottr
412 1.3 chs tstb %a0@(ph3H) | LSTRB high
413 1.1 scottr #if USE_DELAY
414 1.3 chs movel #1000,%sp@- | delay 1 ms
415 1.1 scottr jsr _C_LABEL(delay)
416 1.3 chs addqw #4,%sp | clean up stack
417 1.1 scottr #else
418 1.3 chs movew #1,%d0
419 1.1 scottr bsr iwmDelay
420 1.1 scottr #endif
421 1.3 chs tstb %a0@(ph3L) | LSTRB low
422 1.3 chs moveq #0,%d0 | All's well...
423 1.1 scottr ejDone:
424 1.3 chs 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.3 chs * Returns: %d0 drive #
433 1.1 scottr */
434 1.1 scottr ENTRY(iwmSelectDrive)
435 1.3 chs link %a6,#0
436 1.3 chs moveml %a0-%a1,%sp@-
437 1.3 chs movel _C_LABEL(IWMBase),%a0
438 1.3 chs movel _C_LABEL(Via1Base),%a1
439 1.1 scottr
440 1.3 chs movel %a6@(8),%d0 | Get drive #
441 1.1 scottr bne extDrv
442 1.3 chs tstb %a0@(intDrive)
443 1.1 scottr bra sdDone
444 1.1 scottr extDrv:
445 1.3 chs tstb %a0@(extDrive)
446 1.1 scottr sdDone:
447 1.3 chs moveml %sp@+,%a0-%a1
448 1.3 chs 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.3 chs * Returns: %d0 motor cmd
458 1.1 scottr */
459 1.1 scottr ENTRY(iwmMotor)
460 1.3 chs link %a6,#0
461 1.3 chs moveml %a0-%a1,%sp@-
462 1.3 chs movel _C_LABEL(IWMBase),%a0
463 1.3 chs movel _C_LABEL(Via1Base),%a1
464 1.1 scottr
465 1.3 chs movel %a6@(8),%d0 | Get drive #
466 1.1 scottr bne mtDrv1
467 1.3 chs tstb %a0@(intDrive)
468 1.1 scottr bra mtSwitch
469 1.1 scottr mtDrv1:
470 1.3 chs tstb %a0@(extDrive)
471 1.1 scottr mtSwitch:
472 1.3 chs movel #motorOnCmd,%d0 | Motor ON
473 1.3 chs tstl %a6@(12)
474 1.1 scottr bne mtON
475 1.3 chs movel #motorOffCmd,%d0
476 1.1 scottr mtON:
477 1.1 scottr bsr driveCmd
478 1.1 scottr
479 1.3 chs moveml %sp@+,%a0-%a1
480 1.3 chs 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.3 chs link %a6,#0
494 1.3 chs moveml %d1/%a0-%a1,%sp@-
495 1.3 chs movel _C_LABEL(IWMBase),%a0
496 1.3 chs movel _C_LABEL(Via1Base),%a1
497 1.1 scottr
498 1.3 chs 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.3 chs moveq #rdDataFrom0,%d0 | Lower head
505 1.3 chs movel %a6@(0x08),%d1 | Get side #
506 1.1 scottr beq ssSide0
507 1.3 chs moveq #rdDataFrom1,%d0 | Upper head
508 1.1 scottr ssSide0:
509 1.1 scottr bsr driveStat
510 1.1 scottr
511 1.3 chs moveml %sp@+,%d1/%a0-%a1
512 1.3 chs 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.3 chs * Returns: %d0 result code
523 1.1 scottr */
524 1.1 scottr ENTRY(iwmTrack00)
525 1.3 chs link %a6,#0
526 1.3 chs moveml %d1-%d4/%a0-%a1,%sp@-
527 1.3 chs movel _C_LABEL(IWMBase),%a0
528 1.3 chs movel _C_LABEL(Via1Base),%a1
529 1.1 scottr
530 1.3 chs moveq #motorOnCmd,%d0 | Switch drive motor on
531 1.1 scottr bsr driveCmd
532 1.1 scottr
533 1.3 chs moveq #stepOutCmd,%d0 | Step out
534 1.1 scottr bsr driveCmd
535 1.1 scottr
536 1.3 chs movew #100,%d2 | Max. tries
537 1.1 scottr t0Retry:
538 1.3 chs 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.3 chs moveq #doStepCmd,%d0 | otherwise step
543 1.1 scottr bsr driveCmd
544 1.3 chs movew #80,%d4 | Retries
545 1.1 scottr t0Still:
546 1.3 chs moveq #stillStepping,%d0 | Drive is still stepping?
547 1.1 scottr bsr driveStat
548 1.3 chs dbmi %d4,t0Still
549 1.1 scottr
550 1.3 chs cmpiw #-1,%d4
551 1.1 scottr bne t002
552 1.1 scottr
553 1.3 chs 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.3 chs movel #15000,%sp@-
559 1.1 scottr jsr _C_LABEL(delay) | in mac68k/clock.c
560 1.3 chs addqw #4,%sp
561 1.1 scottr #else
562 1.3 chs movew #15,%d0
563 1.1 scottr bsr iwmDelay
564 1.1 scottr #endif
565 1.1 scottr
566 1.3 chs dbra %d2,t0Retry
567 1.1 scottr
568 1.3 chs 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.3 chs moveq #0,%d0
573 1.1 scottr t0Done:
574 1.3 chs moveml %sp@+,%d1-%d4/%a0-%a1
575 1.3 chs unlk %a6
576 1.3 chs 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.3 chs * returns: %d0 result code
584 1.1 scottr */
585 1.1 scottr ENTRY(iwmSeek)
586 1.3 chs link %a6,#0
587 1.3 chs moveml %d1-%d4/%a0-%a1,%sp@-
588 1.3 chs movel _C_LABEL(IWMBase),%a0
589 1.3 chs movel _C_LABEL(Via1Base),%a1
590 1.1 scottr
591 1.3 chs moveq #motorOnCmd,%d0 | Switch drive motor on
592 1.1 scottr bsr driveCmd
593 1.1 scottr
594 1.3 chs moveq #stepInCmd,%d0 | Set step IN
595 1.3 chs 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.3 chs moveq #stepOutCmd,%d0 | Set step OUT
600 1.3 chs negl %d2 | Make # of steps positive
601 1.1 scottr stepOut:
602 1.3 chs subql #1,%d2 | Loop exits for -1
603 1.1 scottr bsr driveCmd | Set direction
604 1.1 scottr stLoop:
605 1.3 chs moveq #doStepCmd,%d0
606 1.1 scottr bsr driveCmd | Step one!
607 1.3 chs movew #80,%d4 | Retries
608 1.1 scottr st01:
609 1.3 chs moveq #stillStepping, %d0 | Drive is still stepping?
610 1.1 scottr bsr driveStat
611 1.3 chs dbmi %d4,st01
612 1.1 scottr
613 1.3 chs cmpiw #-1,%d4
614 1.1 scottr bne st02
615 1.1 scottr
616 1.3 chs 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.3 chs movel #30,%sp@-
622 1.1 scottr jsr _C_LABEL(delay) | in mac68k/clock.c
623 1.3 chs addqw #4,%sp
624 1.1 scottr #else
625 1.3 chs movew _C_LABEL(TimeDBRA),%d4 | dbra loops per ms
626 1.3 chs lsrw #5,%d4 | DIV 32
627 1.3 chs st03: dbra %d4,st03 | makes ca. 30 us
628 1.1 scottr #endif
629 1.1 scottr
630 1.3 chs dbra %d2,stLoop
631 1.1 scottr
632 1.3 chs moveq #0,%d2 | All is well
633 1.1 scottr stDone:
634 1.3 chs movel %d2,%d0
635 1.3 chs moveml %sp@+,%d1-%d4/%a0-%a1
636 1.3 chs 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.2 scottr * XXX make "sizeof cylCache_t" a symbolic constant
648 1.2 scottr *
649 1.3 chs * Parameters: %fp+08 l Address of sector data buffer (512 bytes)
650 1.3 chs * %fp+12 l Address of sector header struct (I/O)
651 1.3 chs * %fp+16 l Address of cache buffer ptr array
652 1.3 chs * Returns: %d0 result code
653 1.3 chs * Local: %fp-2 w CPU status register
654 1.3 chs * %fp-3 b side,
655 1.3 chs * %fp-4 b track,
656 1.3 chs * %fp-5 b sector wanted
657 1.3 chs * %fp-6 b retry count
658 1.3 chs * %fp-7 b sector read
659 1.1 scottr */
660 1.1 scottr ENTRY(iwmReadSector)
661 1.3 chs link %a6,#-8
662 1.3 chs moveml %d1-%d7/%a0-%a5,%sp@-
663 1.1 scottr
664 1.3 chs movel _C_LABEL(Via1Base),%a1
665 1.3 chs movel %a6@(o_hdr),%a4 | Addr of sector header struct
666 1.1 scottr
667 1.3 chs moveb %a4@+,%a6@(-3) | Save side bit,
668 1.3 chs moveb %a4@+,%a6@(-4) | track#,
669 1.3 chs moveb %a4@,%a6@(-5) | sector#
670 1.3 chs moveb #2*maxGCRSectors,%a6@(-6) | Max. retry count
671 1.1 scottr
672 1.3 chs movew %sr,%a6@(-2) | Save CPU status register
673 1.3 chs oriw #0x0600,%sr | Block all interrupts
674 1.1 scottr
675 1.2 scottr rsNextSect:
676 1.3 chs 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.3 chs movel %a6@(o_hdr),%a4 | Sector header struct
684 1.1 scottr
685 1.3 chs moveb %a4@(o_side),%d1 | Get actual side
686 1.3 chs lsrb #3,%d1 | "Normalize" side bit (to bit 0)
687 1.3 chs andb #1,%d1
688 1.3 chs moveb %a6@(-3),%d2 | Get wanted side
689 1.3 chs eorb %d1,%d2 | Compare side bits
690 1.1 scottr bne rsSeekErr | Should be equal!
691 1.1 scottr
692 1.3 chs moveb %a6@(-4),%d1 | Get track# we want
693 1.3 chs cmpb %a4@(o_track),%d1 | Compare to the header we've read
694 1.1 scottr beq rsGetSect
695 1.2 scottr
696 1.1 scottr rsSeekErr:
697 1.3 chs 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.3 chs * %a0 points to data register of IWM as set up by readSectHdr
704 1.3 chs * %a2 points to 'diskTo' translation table
705 1.3 chs * %a4 points to tags buffer
706 1.1 scottr */
707 1.1 scottr rsGetSect:
708 1.3 chs moveb %a4@(2),%a6@(-7) | save sector number
709 1.3 chs lea %a4@(3),%a4 | Beginning of tag buffer
710 1.3 chs moveq #50,%d3 | Max. retries for sector lookup
711 1.1 scottr rsLeadIn:
712 1.3 chs lea dataLeadIn,%a3 | Sector data lead-in
713 1.3 chs moveq #0x03,%d4 | is 3 bytes long
714 1.1 scottr rsLI1:
715 1.3 chs moveb %a0@,%d2 | Get next byte
716 1.1 scottr bpl rsLI1
717 1.3 chs dbra %d3,rsLI2
718 1.3 chs 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.3 chs cmpb %a3@+,%d2
723 1.1 scottr bne rsLeadIn | If ne restart scan
724 1.3 chs subqw #1,%d4
725 1.1 scottr bne rsLI1
726 1.2 scottr
727 1.1 scottr /*
728 1.1 scottr * We have found the lead-in. Now get the 12 tag bytes.
729 1.3 chs * (We leave %a3 pointing to 'dataLeadOut' for later.)
730 1.1 scottr */
731 1.1 scottr rsTagNyb0:
732 1.3 chs moveb %a0@,%d3 | Get a char,
733 1.1 scottr bpl rsTagNyb0
734 1.3 chs moveb %a2@(0,%d3),%a4@+ | remap and store it
735 1.1 scottr
736 1.3 chs moveq #0,%d5 | Clear checksum registers
737 1.3 chs moveq #0,%d6
738 1.3 chs moveq #0,%d7
739 1.3 chs moveq #10,%d4 | Loop counter
740 1.3 chs moveq #0,%d3 | Data scratch reg
741 1.1 scottr
742 1.1 scottr rsTags:
743 1.1 scottr rsTagNyb1:
744 1.3 chs moveb %a0@,%d3 | Get 2 bit nibbles
745 1.1 scottr bpl rsTagNyb1
746 1.3 chs moveb %a2@(0,%d3),%d1 | Remap disk byte
747 1.3 chs rolb #2,%d1
748 1.3 chs moveb %d1,%d2
749 1.3 chs andib #0xC0,%d2 | Get top 2 bits for first byte
750 1.1 scottr rsTagNyb2:
751 1.3 chs moveb %a0@,%d3 | Get first 6 bit nibble
752 1.1 scottr bpl rsTagNyb2
753 1.3 chs orb %a2@(0,%d3),%d2 | Remap it and complete first byte
754 1.1 scottr
755 1.3 chs moveb %d7,%d3 | The X flag bit (a copy of the carry
756 1.3 chs addb %d7,%d3 | flag) is added with the next addx
757 1.1 scottr
758 1.3 chs rolb #1,%d7
759 1.3 chs eorb %d7,%d2
760 1.3 chs moveb %d2,%a4@+ | Store tag byte
761 1.3 chs addxb %d2,%d5 | See above
762 1.3 chs
763 1.3 chs rolb #2,%d1
764 1.3 chs moveb %d1,%d2
765 1.3 chs andib #0xC0,%d2 | Get top 2 bits for second byte
766 1.1 scottr rsTagNyb3:
767 1.3 chs moveb %a0@,%d3 | Get second 6 bit nibble
768 1.1 scottr bpl rsTagNyb3
769 1.3 chs orb %a2@(0,%d3),%d2 | remap it and complete byte
770 1.3 chs eorb %d5,%d2
771 1.3 chs moveb %d2,%a4@+ | Store tag byte
772 1.3 chs addxb %d2,%d6
773 1.1 scottr
774 1.3 chs rolb #2,%d1
775 1.3 chs andib #0xC0,%d1 | Get top 2 bits for third byte
776 1.1 scottr rsTagNyb4:
777 1.3 chs moveb %a0@,%d3 | Get third 6 bit nibble
778 1.1 scottr bpl rsTagNyb4
779 1.3 chs orb %a2@(0,%d3),%d1 | remap it and complete byte
780 1.3 chs eorb %d6,%d1
781 1.3 chs moveb %d1,%a4@+ | Store tag byte
782 1.3 chs addxb %d1,%d7
783 1.1 scottr
784 1.3 chs subqw #3,%d4 | Update byte counter (four 6&2 encoded
785 1.1 scottr bpl rsTags | disk bytes make three data bytes).
786 1.2 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.2 scottr * Compare sector # to what we wanted: If it matches, read directly
793 1.2 scottr * to buffer, else read to track cache.
794 1.1 scottr */
795 1.3 chs movew #0x01FE,%d4 | Loop counter
796 1.3 chs moveq #0,%d1 | Clear %d1
797 1.3 chs moveb %a6@(-7),%d1 | Get sector# we have read
798 1.3 chs cmpb %a6@(-5),%d1 | Compare to the sector# we want
799 1.2 scottr bne rsToCache
800 1.3 chs movel %a6@(o_buf),%a4 | Sector data buffer
801 1.2 scottr bra rsData
802 1.2 scottr rsToCache:
803 1.3 chs movel %a6@(o_rslots),%a4 | Base address of slot array
804 1.3 chs lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
805 1.3 chs movel #-1,%a4@(o_valid,%d1)
806 1.3 chs movel %a4@(o_secbuf,%d1),%a4 | and get its buffer ptr
807 1.1 scottr rsData:
808 1.1 scottr rsDatNyb1:
809 1.3 chs moveb %a0@,%d3 | Get 2 bit nibbles
810 1.1 scottr bpl rsDatNyb1
811 1.3 chs moveb %a2@(0,%d3),%d1 | Remap disk byte
812 1.3 chs rolb #2,%d1
813 1.3 chs moveb %d1,%d2
814 1.3 chs andib #0xC0,%d2 | Get top 2 bits for first byte
815 1.1 scottr rsDatNyb2:
816 1.3 chs moveb %a0@,%d3 | Get first 6 bit nibble
817 1.1 scottr bpl rsDatNyb2
818 1.3 chs orb %a2@(0,%d3),%d2 | Remap it and complete first byte
819 1.1 scottr
820 1.3 chs moveb %d7,%d3 | The X flag bit (a copy of the carry
821 1.3 chs addb %d7,%d3 | flag) is added with the next addx
822 1.1 scottr
823 1.3 chs rolb #1,%d7
824 1.3 chs eorb %d7,%d2
825 1.3 chs moveb %d2,%a4@+ | Store data byte
826 1.3 chs addxb %d2,%d5 | See above
827 1.3 chs
828 1.3 chs rolb #2,%d1
829 1.3 chs moveb %d1,%d2
830 1.3 chs andib #0xC0,%d2 | Get top 2 bits for second byte
831 1.1 scottr rsDatNyb3:
832 1.3 chs moveb %a0@,%d3 | Get second 6 bit nibble
833 1.1 scottr bpl rsDatNyb3
834 1.3 chs orb %a2@(0,%d3),%d2 | Remap it and complete byte
835 1.3 chs eorb %d5,%d2
836 1.3 chs moveb %d2,%a4@+ | Store data byte
837 1.3 chs addxb %d2,%d6
838 1.3 chs tstw %d4
839 1.1 scottr beq rsCkSum | Data read, continue with checksums
840 1.1 scottr
841 1.3 chs rolb #2,%d1
842 1.3 chs andib #0xC0,%d1 | Get top 2 bits for third byte
843 1.1 scottr rsDatNyb4:
844 1.3 chs moveb %a0@,%d3 | Get third 6 bit nibble
845 1.1 scottr bpl rsDatNyb4
846 1.3 chs orb %a2@(0,%d3),%d1 | Remap it and complete byte
847 1.3 chs eorb %d6,%d1
848 1.3 chs moveb %d1,%a4@+ | Store data byte
849 1.3 chs addxb %d1,%d7
850 1.3 chs 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.3 chs * maintained in %D5/%D6/%D7 for the 1st/2nd/3rd data byte of
857 1.3 chs * each group.
858 1.1 scottr */
859 1.1 scottr rsCkSum:
860 1.1 scottr rsCkS1:
861 1.3 chs moveb %a0@,%d3 | Get 2 bit nibbles
862 1.1 scottr bpl rsCkS1
863 1.3 chs moveb %a2@(0,%d3),%d1 | Remap disk byte
864 1.1 scottr bmi rsBadCkSum | Fault! (Bad read)
865 1.3 chs rolb #2,%d1
866 1.3 chs moveb %d1,%d2
867 1.3 chs andib #0xC0,%d2 | Get top 2 bits for first byte
868 1.1 scottr rsCkS2:
869 1.3 chs moveb %a0@,%d3 | Get first 6 bit nibble
870 1.1 scottr bpl rsCkS2
871 1.3 chs moveb %a2@(0,%d3),%d3 | and remap it
872 1.1 scottr bmi rsBadCkSum | Fault! ( > 0x3f is bad read)
873 1.3 chs orb %d3,%d2 | Merge 6&2
874 1.3 chs cmpb %d2,%d5 | Compare first checksum to %D5
875 1.1 scottr bne rsBadCkSum | Fault! (Checksum)
876 1.1 scottr
877 1.3 chs rolb #2,%d1
878 1.3 chs moveb %d1,%d2
879 1.3 chs andib #0xC0,%d2 | Get top 2 bits for second byte
880 1.1 scottr rsCkS3:
881 1.3 chs moveb %a0@,%d3 | Get second 6 bit nibble
882 1.1 scottr bpl rsCkS3
883 1.3 chs moveb %a2@(0,%d3),%d3 | and remap it
884 1.1 scottr bmi rsBadCkSum | Fault! (Bad read)
885 1.3 chs orb %d3,%d2 | Merge 6&2
886 1.3 chs cmpb %d2,%d6 | Compare second checksum to %D6
887 1.1 scottr bne rsBadCkSum | Fault! (Checksum)
888 1.1 scottr
889 1.3 chs rolb #2,%d1
890 1.3 chs andib #0xC0,%d1 | Get top 2 bits for second byte
891 1.1 scottr rsCkS4:
892 1.3 chs moveb %a0@,%d3 | Get third 6 bit nibble
893 1.1 scottr bpl rsCkS4
894 1.3 chs moveb %a2@(0,%d3),%d3 | and remap it
895 1.1 scottr bmi rsBadCkSum | Fault! (Bad read)
896 1.3 chs orb %d3,%d1 | Merge 6&2
897 1.3 chs cmpb %d1,%d7 | Compare third checksum to %D7
898 1.1 scottr beq rsLdOut | Fault! (Checksum)
899 1.1 scottr
900 1.1 scottr rsBadCkSum:
901 1.3 chs moveq #badDCkSum,%d0 | Bad data mark checksum
902 1.1 scottr bra rsDone
903 1.1 scottr
904 1.1 scottr rsBadDBtSlp:
905 1.3 chs moveq #badDBtSlp,%d0 | One of the data mark bit slip
906 1.1 scottr bra rsDone | nibbles was incorrect
907 1.1 scottr
908 1.1 scottr /*
909 1.1 scottr * We have gotten the checksums allright, now look for the
910 1.1 scottr * sector data lead-out 'DE AA'
911 1.3 chs * (We have %a3 still pointing to 'dataLeadOut'; this part of the
912 1.1 scottr * table is used for writing to disk, too.)
913 1.1 scottr */
914 1.1 scottr rsLdOut:
915 1.3 chs moveq #1,%d4 | Is two bytes long {1,0}
916 1.1 scottr rsLdOut1:
917 1.3 chs moveb %a0@,%d3 | Get token
918 1.1 scottr bpl rsLdOut1
919 1.3 chs cmpb %a3@+,%d3
920 1.1 scottr bne rsBadDBtSlp | Fault!
921 1.3 chs dbra %d4,rsLdOut1
922 1.3 chs moveq #0,%d0 | OK.
923 1.2 scottr
924 1.2 scottr /*
925 1.2 scottr * See if we got the sector we wanted. If not, and no error
926 1.2 scottr * occurred, mark buffer valid. Else ignore the sector.
927 1.2 scottr * Then, read on.
928 1.2 scottr */
929 1.1 scottr rsDone:
930 1.3 chs movel %a6@(o_hdr),%a4 | Addr of sector header struct
931 1.3 chs moveb %a4@(o_sector),%d1 | Get # of sector we have just read
932 1.3 chs cmpb %a6@(-5),%d1 | Compare to the sector we want
933 1.2 scottr beq rsAllDone
934 1.2 scottr
935 1.3 chs tstb %d0 | Any error? Simply ignore data
936 1.2 scottr beq rsBufValid
937 1.3 chs lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
938 1.3 chs movel %a6@(o_rslots),%a4
939 1.3 chs clrl %a4@(o_valid,%d1) | Mark buffer content "invalid"
940 1.2 scottr
941 1.2 scottr rsBufValid:
942 1.3 chs subqb #1,%a6@(-6) | max. retries
943 1.2 scottr bne rsNextSect
944 1.2 scottr | Sector not found, but
945 1.3 chs tstb %d0 | don't set error code if we
946 1.2 scottr bne rsAllDone | already have one.
947 1.3 chs moveq #sectNFErr,%d0
948 1.2 scottr rsAllDone:
949 1.3 chs movew %a6@(-2),%sr | Restore interrupt mask
950 1.3 chs moveml %sp@+,%d1-%d7/%a0-%a5
951 1.3 chs unlk %a6
952 1.2 scottr rts
953 1.1 scottr
954 1.1 scottr
955 1.1 scottr /*
956 1.1 scottr * iwmWriteSector -- encode and write data to the specified sector.
957 1.1 scottr *
958 1.1 scottr * TODO: Poll SCC as long as interrupts are disabled (see top comment)
959 1.1 scottr * Understand and document the checksum algorithm!
960 1.1 scottr *
961 1.2 scottr * XXX Use registers more efficiently
962 1.2 scottr *
963 1.3 chs * Parameters: %fp+8 l Address of sector header struct (I/O)
964 1.3 chs * %fp+12 l Address of cache buffer ptr array
965 1.3 chs * Returns: %d0 result code
966 1.3 chs *
967 1.3 chs * Local: %fp-2 w CPU status register
968 1.3 chs * %fp-3 b side,
969 1.3 chs * %fp-4 b track,
970 1.3 chs * %fp-5 b sector wanted
971 1.3 chs * %fp-6 b retry count
972 1.3 chs * %fp-10 b current slot
973 1.1 scottr */
974 1.1 scottr ENTRY(iwmWriteSector)
975 1.3 chs link %a6,#-10
976 1.3 chs moveml %d1-%d7/%a0-%a5,%sp@-
977 1.1 scottr
978 1.3 chs movel _C_LABEL(Via1Base),%a1
979 1.3 chs movel %a6@(o_hdr),%a4 | Addr of sector header struct
980 1.1 scottr
981 1.3 chs moveb %a4@+,%a6@(-3) | Save side bit,
982 1.3 chs moveb %a4@+,%a6@(-4) | track#,
983 1.3 chs moveb %a4@,%a6@(-5) | sector#
984 1.3 chs moveb #maxGCRSectors,%a6@(-6) | Max. retry count
985 1.1 scottr
986 1.3 chs movew %sr,%a6@(-2) | Save CPU status register
987 1.3 chs oriw #0x0600,%sr | Block all interrupts
988 1.1 scottr
989 1.2 scottr wsNextSect:
990 1.3 chs movel %a6@(o_hdr),%a4
991 1.1 scottr bsr readSectHdr | Get next available sector header
992 1.2 scottr bne wsAllDone | Return if error
993 1.1 scottr
994 1.1 scottr /*
995 1.1 scottr * Is this the right track & side? If not, return with error
996 1.1 scottr */
997 1.3 chs movel %a6@(o_hdr),%a4 | Sector header struct
998 1.1 scottr
999 1.3 chs moveb %a4@(o_side),%d1 | Get side#
1000 1.3 chs lsrb #3,%d1 | "Normalize" side bit...
1001 1.3 chs andb #1,%d1
1002 1.3 chs moveb %a6@(-3),%d2 | Get wanted side
1003 1.3 chs eorb %d1,%d2 | Compare side bits
1004 1.1 scottr bne wsSeekErr
1005 1.1 scottr
1006 1.3 chs moveb %a6@(-4),%d1 | Get wanted track#
1007 1.3 chs cmpb %a4@(o_track),%d1 | Compare to the read header
1008 1.1 scottr beq wsCompSect
1009 1.1 scottr
1010 1.1 scottr wsSeekErr:
1011 1.3 chs moveq #seekErr,%d0 | Wrong track or side
1012 1.2 scottr bra wsAllDone
1013 1.1 scottr
1014 1.1 scottr /*
1015 1.2 scottr * Look up the current sector number in the cache.
1016 1.2 scottr * If the buffer is dirty ("valid"), write it to disk. If not,
1017 1.2 scottr * loop over all the slots and return if all of them are clean.
1018 1.2 scottr *
1019 1.2 scottr * Alternatively, we could decrement a "dirty sectors" counter here.
1020 1.1 scottr */
1021 1.1 scottr wsCompSect:
1022 1.3 chs moveq #0,%d1 | Clear register
1023 1.3 chs moveb %a4@(o_sector),%d1 | get the # of header read
1024 1.3 chs lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
1025 1.3 chs movel %a6@(o_wslots),%a4
1026 1.3 chs tstl %a4@(o_valid,%d1) | Sector dirty?
1027 1.2 scottr bne wsBufDirty
1028 1.2 scottr
1029 1.3 chs moveq #maxGCRSectors-1,%d2 | Any dirty sectors left?
1030 1.2 scottr wsChkDty:
1031 1.3 chs movew %d2,%d1
1032 1.3 chs lslw #3,%d1 | sizeof cylCacheSlot_t is 8 bytes
1033 1.3 chs tstl %a4@(o_valid,%d1)
1034 1.2 scottr bne wsNextSect | Sector dirty?
1035 1.3 chs dbra %d2,wsChkDty
1036 1.2 scottr
1037 1.2 scottr bra wsAllDone | We are through with this track.
1038 1.2 scottr
1039 1.1 scottr
1040 1.1 scottr /*
1041 1.1 scottr * Write sync pattern and sector data lead-in 'D5 AA'. The
1042 1.1 scottr * missing 'AD' is made up by piping 0x0B through the nibble
1043 1.1 scottr * table (toDisk).
1044 1.1 scottr *
1045 1.1 scottr * To set up IWM for writing:
1046 1.1 scottr *
1047 1.1 scottr * access q6H & write first byte to q7H.
1048 1.1 scottr * Then check bit 7 of q6L (status reg) for 'IWM ready'
1049 1.1 scottr * and write subsequent bytes to q6H.
1050 1.1 scottr *
1051 1.1 scottr * Registers:
1052 1.3 chs * %a0 IWM base address (later: data register)
1053 1.3 chs * %a1 Via1Base
1054 1.3 chs * %a2 IWM handshake register
1055 1.3 chs * %a3 data (tags buffer, data buffer)
1056 1.3 chs * %a4 Sync pattern, 'toDisk' translation table
1057 1.1 scottr */
1058 1.2 scottr wsBufDirty:
1059 1.3 chs movel _C_LABEL(IWMBase),%a0
1060 1.3 chs lea %a4@(0,%d1),%a3
1061 1.3 chs movel %a3,%a6@(-10) | Save ptr to current slot
1062 1.3 chs tstb %a0@(q6H) | Enable writing to disk
1063 1.3 chs movel %a6@(o_hdr),%a4 | Sector header struct
1064 1.3 chs lea %a4@(o_Tags),%a3 | Point %a3 to tags buffer
1065 1.3 chs lea syncPattern,%a4
1066 1.3 chs
1067 1.3 chs moveb %a4@+,%a0@(q7H) | Write first sync byte
1068 1.3 chs lea %a0@(q6L),%a2 | Point %a2 to handshake register
1069 1.3 chs lea %a0@(q6H),%a0 | Point %a0 to IWM data register
1070 1.3 chs
1071 1.3 chs moveq #6,%d0 | Loop counter for sync bytes
1072 1.3 chs moveq #0,%d2
1073 1.3 chs moveq #0,%d3
1074 1.3 chs movel #0x02010009,%d4 | Loop counters for tag/sector data
1075 1.1 scottr
1076 1.1 scottr /*
1077 1.1 scottr * Write 5 sync bytes and first byte of sector data lead-in
1078 1.1 scottr */
1079 1.1 scottr wsLeadIn:
1080 1.3 chs moveb %a4@+,%d1 | Get next sync byte
1081 1.1 scottr wsLI1:
1082 1.3 chs tstb %a2@ | IWM ready?
1083 1.1 scottr bpl wsLI1
1084 1.3 chs moveb %d1,%a0@ | Write it to disk
1085 1.3 chs subqw #1,%d0
1086 1.1 scottr bne wsLeadIn
1087 1.1 scottr
1088 1.3 chs moveb %a4@+,%d1 | Write 2nd byte of sector lead-in
1089 1.3 chs lea toDisk,%a4 | Point %a4 to nibble translation table
1090 1.1 scottr wsLI2:
1091 1.3 chs tstb %a2@ | IWM ready?
1092 1.1 scottr bpl wsLI2
1093 1.3 chs moveb %d1,%a0@ | Write it to disk
1094 1.1 scottr
1095 1.3 chs moveq #0,%d5 | Clear checksum registers
1096 1.3 chs moveq #0,%d6
1097 1.3 chs moveq #0,%d7
1098 1.1 scottr
1099 1.3 chs moveq #0x0B,%d1 | 3rd byte of sector data lead-in
1100 1.1 scottr | (Gets translated to 0xAD)
1101 1.3 chs moveb %a3@+,%d2 | Get 1st byte from tags buffer
1102 1.1 scottr bra wsDataEntry
1103 1.1 scottr
1104 1.1 scottr /*
1105 1.1 scottr * The following loop reads the content of the tags buffer (12 bytes)
1106 1.1 scottr * and the data buffer (512 bytes).
1107 1.1 scottr * Each pass reads out three bytes and
1108 1.1 scottr * a) splits them 6&2 into three 6 bit nibbles and a fourth byte
1109 1.1 scottr * consisting of the three 2 bit nibbles
1110 1.1 scottr * b) encodes the nibbles with a table to disk bytes (bit 7 set, no
1111 1.1 scottr * more than two consecutive zero bits) and writes them to disk as
1112 1.1 scottr *
1113 1.1 scottr * 00mmnnoo fragment 2 bit nibbles
1114 1.1 scottr * 00mmmmmm 6 bit nibble -- first byte
1115 1.1 scottr * 00nnnnnn 6 bit nibble -- second byte
1116 1.1 scottr * 00oooooo 6 bit nibble -- third byte
1117 1.1 scottr *
1118 1.1 scottr * c) adds up three 8 bit checksums, one for each of the bytes written.
1119 1.1 scottr */
1120 1.2 scottr wsSD1:
1121 1.3 chs movel %a6@(-10),%a3 | Get ptr to current slot
1122 1.3 chs movel %a3@(o_secbuf),%a3 | Get start of sector data buffer
1123 1.1 scottr
1124 1.1 scottr wsData:
1125 1.3 chs addxb %d2,%d7
1126 1.3 chs eorb %d6,%d2
1127 1.3 chs moveb %d2,%d3
1128 1.3 chs lsrw #6,%d3 | Put 2 bit nibbles into place
1129 1.1 scottr wsRDY01:
1130 1.3 chs tstb %a2@ | IWM ready?
1131 1.1 scottr bpl wsRDY01
1132 1.3 chs moveb %a4@(0,%d3),%a0@ | Translate nibble and write
1133 1.3 chs subqw #3,%d4 | Update counter
1134 1.3 chs moveb %d7,%d3
1135 1.3 chs addb %d7,%d3 | Set X flag (??)
1136 1.3 chs rolb #1,%d7
1137 1.3 chs andib #0x3F,%d0
1138 1.1 scottr wsRDY02:
1139 1.3 chs tstb %a2@ | IWM ready?
1140 1.1 scottr bpl wsRDY02
1141 1.3 chs moveb %a4@(0,%d0),%a0@ | Translate nibble and write
1142 1.1 scottr
1143 1.1 scottr /*
1144 1.1 scottr * We enter with the last byte of the sector data lead-in
1145 1.3 chs * between our teeth (%D1, that is).
1146 1.1 scottr */
1147 1.1 scottr wsDataEntry:
1148 1.3 chs moveb %a3@+,%d0 | Get first byte
1149 1.3 chs addxb %d0,%d5
1150 1.3 chs eorb %d7,%d0
1151 1.3 chs moveb %d0,%d3 | Keep top two bits
1152 1.3 chs rolw #2,%d3 | by shifting them to MSByte
1153 1.3 chs andib #0x3F,%d1
1154 1.1 scottr wsRDY03:
1155 1.3 chs tstb %a2@ | IWM ready?
1156 1.1 scottr bpl wsRDY03
1157 1.3 chs moveb %a4@(0,%d1),%a0@ | Translate nibble and write
1158 1.1 scottr
1159 1.3 chs moveb %a3@+,%d1 | Get second byte
1160 1.3 chs addxb %d1,%d6
1161 1.3 chs eorb %d5,%d1
1162 1.3 chs moveb %d1,%d3 | Keep top two bits
1163 1.3 chs rolw #2,%d3 | by shifting them to MSByte
1164 1.3 chs andib #0x3F,%d2
1165 1.1 scottr wsRDY04:
1166 1.3 chs tstb %a2@ | IWM ready?
1167 1.1 scottr bpl wsRDY04
1168 1.3 chs moveb %a4@(0,%d2),%a0@ | Translate nibble and write
1169 1.2 scottr
1170 1.1 scottr /*
1171 1.1 scottr * XXX We have a classic off-by-one error here: the last access
1172 1.1 scottr * reaches beyond the data buffer which bombs with memory
1173 1.1 scottr * protection. The value read isn't used anyway...
1174 1.1 scottr * Hopefully there is enough time for an additional check
1175 1.1 scottr * (exit the last loop cycle before the buffer access).
1176 1.1 scottr */
1177 1.3 chs tstl %d4 | Last loop cycle?
1178 1.1 scottr beq wsSDDone | Then get out while we can.
1179 1.1 scottr
1180 1.3 chs moveb %a3@+,%d2 | Get third byte
1181 1.3 chs tstw %d4 | First write tag buffer,...
1182 1.1 scottr bne wsData
1183 1.1 scottr
1184 1.3 chs swap %d4 | ...then write data buffer
1185 1.1 scottr bne wsSD1
1186 1.1 scottr
1187 1.1 scottr /*
1188 1.1 scottr * Write nibbles for last 2 bytes, then
1189 1.1 scottr * split checksum bytes in 6&2 and write them to disk
1190 1.1 scottr */
1191 1.1 scottr wsSDDone:
1192 1.3 chs clrb %d3 | No 513th byte
1193 1.3 chs lsrw #6,%d3 | Set up 2 bit nibbles
1194 1.1 scottr wsRDY05:
1195 1.3 chs tstb %a2@ | IWM ready?
1196 1.1 scottr bpl wsRDY05
1197 1.3 chs moveb %a4@(0,%d3),%a0@ | Write fragments
1198 1.3 chs moveb %d5,%d3
1199 1.3 chs rolw #2,%d3
1200 1.3 chs moveb %d6,%d3
1201 1.3 chs rolw #2,%d3
1202 1.3 chs andib #0x3F,%d0
1203 1.1 scottr wsRDY06:
1204 1.3 chs tstb %a2@ | IWM ready?
1205 1.1 scottr bpl wsRDY06
1206 1.3 chs moveb %a4@(0,%d0),%a0@ | Write 511th byte
1207 1.3 chs andib #0x3F,%d1
1208 1.1 scottr wsRDY07:
1209 1.3 chs tstb %a2@ | IWM ready?
1210 1.1 scottr bpl wsRDY07
1211 1.3 chs moveb %a4@(0,%d1),%a0@ | write 512th byte
1212 1.3 chs moveb %d7,%d3
1213 1.3 chs lsrw #6,%d3 | Get fragments ready
1214 1.1 scottr wsRDY08:
1215 1.3 chs tstb %a2@ | IWM ready?
1216 1.1 scottr bpl wsRDY08
1217 1.3 chs moveb %a4@(0,%d3),%a0@ | Write fragments
1218 1.3 chs andib #0x3F,%d5
1219 1.1 scottr wsRDY09:
1220 1.3 chs tstb %a2@ | IWM ready?
1221 1.1 scottr bpl wsRDY09
1222 1.3 chs moveb %a4@(0,%d5),%a0@ | Write first checksum byte
1223 1.3 chs andib #0x3F,%D6
1224 1.1 scottr wsRDY10:
1225 1.3 chs tstb %a2@ | IWM ready?
1226 1.1 scottr bpl wsRDY10
1227 1.3 chs moveb %a4@(0,%d6),%a0@ | Write second checksum byte
1228 1.3 chs andib #0x3F,%d7
1229 1.1 scottr wsRDY11:
1230 1.3 chs tstb %a2@ | IWM ready?
1231 1.1 scottr bpl wsRDY11
1232 1.3 chs moveb %a4@(0,%d7),%a0@ | Write third checksum byte
1233 1.1 scottr
1234 1.1 scottr /*
1235 1.1 scottr * Write sector data lead-out
1236 1.1 scottr */
1237 1.3 chs lea dataLeadOut,%a4 | Sector data lead-out
1238 1.3 chs moveq #3,%d2 | Four bytes long {3,2,1,0}
1239 1.1 scottr wsLeadOut:
1240 1.3 chs moveb %a2@,%d1 | IWM ready?
1241 1.1 scottr bpl wsLeadOut
1242 1.3 chs moveb %a4@+,%a0@ | Write lead-out
1243 1.3 chs dbf %d2,wsLeadOut
1244 1.1 scottr
1245 1.3 chs moveq #0,%d0
1246 1.3 chs btst #6,%d1 | Check IWM underrun bit
1247 1.1 scottr bne wsNoErr
1248 1.1 scottr
1249 1.3 chs moveq #wrUnderRun,%d0 | Could not write
1250 1.1 scottr | fast enough to keep up with IWM
1251 1.1 scottr wsNoErr:
1252 1.3 chs tstb %a0@(0x0200) | q7L -- Write OFF
1253 1.1 scottr
1254 1.1 scottr wsDone:
1255 1.3 chs tstb %d0 | Any error? Simply retry
1256 1.2 scottr bne wsBufInvalid
1257 1.2 scottr
1258 1.3 chs movel %a6@(-10),%a4 | Else, get ptr to current slot
1259 1.3 chs clrl %a4@(o_valid) | Mark current buffer "clean"
1260 1.2 scottr bra wsNextSect
1261 1.2 scottr
1262 1.2 scottr wsBufInvalid:
1263 1.3 chs subqb #1,%a6@(-6) | retries
1264 1.2 scottr bne wsNextSect
1265 1.2 scottr | Sector not found, but
1266 1.3 chs tstb %d0 | don't set error code if we
1267 1.2 scottr bne wsAllDone | already have one.
1268 1.3 chs moveq #sectNFErr,%d0
1269 1.2 scottr
1270 1.2 scottr wsAllDone:
1271 1.3 chs movew %a6@(-2),%sr | Restore interrupt mask
1272 1.3 chs moveml %sp@+,%d1-%d7/%a0-%a5
1273 1.3 chs unlk %a6
1274 1.1 scottr rts
1275 1.1 scottr
1276 1.1 scottr
1277 1.1 scottr
1278 1.1 scottr /**
1279 1.1 scottr ** Local functions
1280 1.1 scottr **/
1281 1.1 scottr
1282 1.1 scottr /*
1283 1.1 scottr * iwmDelay
1284 1.1 scottr *
1285 1.1 scottr * In-kernel calls to delay() in mac68k/clock.c bomb
1286 1.1 scottr *
1287 1.3 chs * Parameters: %d0 delay in milliseconds
1288 1.3 chs * Trashes: %d0, %d1
1289 1.1 scottr * Returns: -
1290 1.1 scottr */
1291 1.1 scottr iwmDelay:
1292 1.1 scottr /* TimeDBRA is ~8K for 040/33 machines, so we need nested loops */
1293 1.3 chs id00: movew _C_LABEL(TimeDBRA),%d1 | dbra loops per ms
1294 1.3 chs id01: dbra %d1,id01 |
1295 1.3 chs dbra %d0,id00
1296 1.1 scottr rts
1297 1.1 scottr
1298 1.1 scottr
1299 1.1 scottr /*
1300 1.1 scottr * selDriveReg -- Select drive status/control register
1301 1.1 scottr *
1302 1.3 chs * Parameters: %d0 register #
1303 1.1 scottr * (bit 0 - CA2, bit 1 - SEL, bit 2 - CA0, bit 3 - CA1)
1304 1.3 chs * %a0 IWM base address
1305 1.3 chs * %a1 VIA base address
1306 1.3 chs * Returns: %d0 register # (unchanged)
1307 1.1 scottr */
1308 1.1 scottr selDriveReg:
1309 1.3 chs tstb %a0@(ph0H) | default CA0 to 1 (says IM III)
1310 1.3 chs tstb %a0@(ph1H) | default CA1 to 1
1311 1.1 scottr
1312 1.3 chs btst #0,%d0 | bit 0 set => CA2 on
1313 1.1 scottr beq se00
1314 1.3 chs tstb %a0@(ph2H)
1315 1.1 scottr bra se01
1316 1.1 scottr se00:
1317 1.3 chs tstb %a0@(ph2L)
1318 1.1 scottr
1319 1.1 scottr se01:
1320 1.3 chs btst #1,%d0 | bit 1 set => SEL on (VIA 1)
1321 1.1 scottr beq se02
1322 1.3 chs bset #vHeadSel,%a1@(vBufA)
1323 1.1 scottr bra se03
1324 1.1 scottr se02:
1325 1.3 chs bclr #vHeadSel,%a1@(vBufA)
1326 1.1 scottr
1327 1.1 scottr se03:
1328 1.3 chs btst #2,%d0 | bit 2 set => CA0 on
1329 1.1 scottr bne se04
1330 1.3 chs tstb %a0@(ph0L)
1331 1.1 scottr
1332 1.1 scottr se04:
1333 1.3 chs btst #3,%d0 | bit 3 set => CA1 on
1334 1.1 scottr bne se05
1335 1.3 chs tstb %a0@(ph1L)
1336 1.1 scottr se05:
1337 1.1 scottr rts
1338 1.1 scottr
1339 1.1 scottr
1340 1.1 scottr
1341 1.1 scottr /*
1342 1.1 scottr * dstatus -- check drive status (bit 7 - N flag) wrt. a previously
1343 1.1 scottr * set status tag.
1344 1.1 scottr *
1345 1.3 chs * Parameters: %d0 register selector
1346 1.3 chs * %a0 IWM base address
1347 1.3 chs * Returns: %d0 status
1348 1.1 scottr */
1349 1.1 scottr dstatus:
1350 1.3 chs tstb %a0@(q6H)
1351 1.3 chs moveb %a0@(q7L),%d0
1352 1.3 chs tstb %a0@(q6L) | leave in "read data reg"
1353 1.3 chs tstb %d0 | state for safety
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.3 chs * Parameters: %a0 IWMBase
1361 1.3 chs * %a1 VIABase
1362 1.3 chs * %d0 register selector
1363 1.3 chs * Returns: %d0 status (Bit 7)
1364 1.1 scottr */
1365 1.1 scottr driveStat:
1366 1.3 chs tstb %a0@(mtrOn) | ENABLE; turn drive on
1367 1.1 scottr bsr selDriveReg
1368 1.1 scottr bsr dstatus
1369 1.1 scottr rts
1370 1.1 scottr
1371 1.1 scottr
1372 1.1 scottr /*
1373 1.1 scottr * dtrigger -- toggle LSTRB line to give drive a strobe signal
1374 1.1 scottr * IM III says pulse length = 1 us < t < 1 ms
1375 1.1 scottr *
1376 1.3 chs * Parameters: %a0 IWMBase
1377 1.3 chs * %a1 VIABase
1378 1.1 scottr * Returns: -
1379 1.1 scottr */
1380 1.1 scottr dtrigger:
1381 1.3 chs tstb %a0@(ph3H) | LSTRB high
1382 1.3 chs moveb %a1@(vBufA),%a1@(vBufA) | intelligent nop seen in q700 ROM
1383 1.3 chs tstb %a0@(ph3L) | LSTRB low
1384 1.1 scottr rts
1385 1.1 scottr
1386 1.1 scottr
1387 1.1 scottr /*
1388 1.1 scottr * driveCmd -- send command to drive.
1389 1.1 scottr *
1390 1.3 chs * Parameters: %a0 IWMBase
1391 1.3 chs * %a1 VIABase
1392 1.3 chs * %d0 Command token
1393 1.1 scottr * Returns: -
1394 1.1 scottr */
1395 1.1 scottr driveCmd:
1396 1.1 scottr bsr selDriveReg
1397 1.1 scottr bsr dtrigger
1398 1.1 scottr rts
1399 1.1 scottr
1400 1.1 scottr
1401 1.1 scottr /*
1402 1.1 scottr * readSectHdr -- read and decode the next available sector header.
1403 1.1 scottr *
1404 1.1 scottr * TODO: Poll SCC as long as interrupts are disabled.
1405 1.1 scottr *
1406 1.3 chs * Parameters: %a4 sectorHdr_t address
1407 1.3 chs * Returns: %d0 result code
1408 1.3 chs * Uses: %d0-%d4, %a0, %a2-%a4
1409 1.1 scottr */
1410 1.1 scottr readSectHdr:
1411 1.3 chs moveq #3,%d4 | Read 3 chars from IWM for sync
1412 1.3 chs movew #600,%d3 | Retries to sync to disk
1413 1.3 chs moveq #0,%d2 | Clear scratch regs
1414 1.3 chs moveq #0,%d1
1415 1.3 chs moveq #0,%d0
1416 1.3 chs movel _C_LABEL(IWMBase),%a0 | IWM base address
1417 1.1 scottr
1418 1.3 chs tstb %a0@(q7L)
1419 1.3 chs lea %a0@(q6L),%a0 | IWM data register
1420 1.1 scottr shReadSy:
1421 1.3 chs moveb %a0@,%d2 | Read char
1422 1.3 chs dbra %d3,shSeekSync
1423 1.1 scottr
1424 1.3 chs moveq #noNybErr,%d0 | Disk is blank?
1425 1.1 scottr bra shDone
1426 1.1 scottr
1427 1.1 scottr shSeekSync:
1428 1.1 scottr bpl shReadSy | No char at IWM, repeat read
1429 1.3 chs subqw #1,%d4
1430 1.1 scottr bne shReadSy
1431 1.1 scottr /*
1432 1.1 scottr * When we get here, the IWM should be in sync with the data
1433 1.1 scottr * stream from disk.
1434 1.1 scottr * Next look for sector header lead-in 'D5 AA 96'
1435 1.1 scottr */
1436 1.3 chs movew #1500,%d3 | Retries to seek header
1437 1.1 scottr shLeadIn:
1438 1.3 chs lea hdrLeadIn,%a3 | Sector header lead-in bytes
1439 1.3 chs moveq #0x03,%d4 | is 3 bytes long
1440 1.1 scottr shLI1:
1441 1.3 chs moveb %a0@,%d2 | Get next byte
1442 1.2 scottr bpl shLI1 | No char at IWM, repeat read
1443 1.3 chs dbra %d3,shLI2
1444 1.3 chs moveq #noAdrMkErr,%d0 | Can't find an address mark
1445 1.1 scottr bra shDone
1446 1.1 scottr
1447 1.1 scottr shLI2:
1448 1.3 chs cmpb %a3@+,%d2
1449 1.1 scottr bne shLeadIn | If ne restart scan
1450 1.3 chs subqw #1,%d4
1451 1.1 scottr bne shLI1
1452 1.1 scottr /*
1453 1.1 scottr * We have found the lead-in. Now get the header information.
1454 1.3 chs * Reg %d4 holds the checksum.
1455 1.1 scottr */
1456 1.3 chs lea diskTo-0x90,%a2 | Translate disk bytes -> 6&2
1457 1.1 scottr shHdr1:
1458 1.3 chs moveb %a0@,%d0 | Get 1st char
1459 1.1 scottr bpl shHdr1
1460 1.3 chs moveb %a2@(0,%d0),%d1 | and remap it
1461 1.3 chs moveb %d1,%d4
1462 1.3 chs rorw #6,%d1 | separate 2:6, drop hi bits
1463 1.1 scottr shHdr2:
1464 1.3 chs moveb %a0@,%d0 | Get 2nd char
1465 1.1 scottr bpl shHdr2
1466 1.3 chs moveb %a2@(0,%d0),%d2 | and remap it
1467 1.3 chs eorb %d2,%d4
1468 1.1 scottr shHdr3:
1469 1.3 chs moveb %a0@,%d0 | Get 3rd char
1470 1.1 scottr bpl shHdr3
1471 1.3 chs moveb %a2@(0,%d0),%d1 | and remap it
1472 1.3 chs eorb %d1,%d4
1473 1.3 chs rolw #6,%d1 |
1474 1.1 scottr shHdr4:
1475 1.3 chs moveb %a0@,%d0 | Get 4th char
1476 1.1 scottr bpl shHdr4
1477 1.3 chs moveb %a2@(0,%d0),%d3 | and remap it
1478 1.3 chs eorb %d3,%d4
1479 1.1 scottr shHdr5:
1480 1.3 chs moveb %a0@,%d0 | Get checksum byte
1481 1.1 scottr bpl shHdr5
1482 1.3 chs moveb %a2@(0,%d0),%d5 | and remap it
1483 1.3 chs eorb %d5,%d4
1484 1.1 scottr bne shCsErr | Checksum ok?
1485 1.1 scottr /*
1486 1.1 scottr * We now have in
1487 1.3 chs * %d1/lsb track number
1488 1.3 chs * %d1/msb bit 3 is side bit
1489 1.3 chs * %d2 sector number
1490 1.3 chs * %d3 ???
1491 1.3 chs * %d5 checksum (=0)
1492 1.1 scottr *
1493 1.1 scottr * Next check for lead-out.
1494 1.1 scottr */
1495 1.3 chs moveq #1,%d4 | is 2 bytes long
1496 1.1 scottr shHdr6:
1497 1.3 chs moveb %a0@,%d0 | Get token
1498 1.1 scottr bpl shHdr6
1499 1.3 chs cmpb %a3@+,%d0 | Check
1500 1.1 scottr bne shLOErr | Fault!
1501 1.3 chs dbra %d4,shHdr6
1502 1.3 chs movew %d1,%d0 | Isolate side bit
1503 1.3 chs lsrw #8,%d0
1504 1.3 chs moveb %d0,%a4@+ | and store it
1505 1.3 chs moveb %d1,%a4@+ | Store track number
1506 1.3 chs moveb %d2,%a4@+ | and sector number
1507 1.3 chs moveq #0,%d0 | All is well
1508 1.1 scottr bra shDone
1509 1.1 scottr
1510 1.1 scottr shCsErr:
1511 1.3 chs moveq #badCkSmErr,%d0 | Bad sector header checksum
1512 1.1 scottr bra shDone
1513 1.1 scottr shLOErr:
1514 1.3 chs moveq #badBtSlpErr,%d0 | Bad address mark (no lead-out)
1515 1.1 scottr
1516 1.1 scottr shDone:
1517 1.3 chs tstl %d0 | Set flags
1518 1.1 scottr rts
1519