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