1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/IoDevice/wd33c93.c,v $
3 **
4 ** $Revision: 1.14 $
5 **
6 ** $Date: 2008-03-30 18:38:41 $
7 **
8 ** Based on the WD33C93 emulation in MESS (www.mess.org).
9 **
10 ** More info: http://www.bluemsx.com
11 **
12 ** Copyright (C) 2003-2006 Daniel Vik, Tomas Karlsson, white cat
13 **
14 ** This program is free software; you can redistribute it and/or modify
15 ** it under the terms of the GNU General Public License as published by
16 ** the Free Software Foundation; either version 2 of the License, or
17 ** (at your option) any later version.
18 **
19 ** This program is distributed in the hope that it will be useful,
20 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 ** GNU General Public License for more details.
23 **
24 ** You should have received a copy of the GNU General Public License
25 ** along with this program; if not, write to the Free Software
26 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 **
28 ******************************************************************************
29 */
30 #include "wd33c93.h"
31 #include "ScsiDefs.h"
32 #include "ScsiDevice.h"
33 #include "ArchCdrom.h"
34 #include "Disk.h"
35 #include "Board.h"
36 #include "SaveState.h"
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 
41 #define REG_OWN_ID      0x00
42 #define REG_CONTROL     0x01
43 #define REG_TIMEO       0x02
44 #define REG_TSECS       0x03
45 #define REG_THEADS      0x04
46 #define REG_TCYL_HI     0x05
47 #define REG_TCYL_LO     0x06
48 #define REG_ADDR_HI     0x07
49 #define REG_ADDR_2      0x08
50 #define REG_ADDR_3      0x09
51 #define REG_ADDR_LO     0x0a
52 #define REG_SECNO       0x0b
53 #define REG_HEADNO      0x0c
54 #define REG_CYLNO_HI    0x0d
55 #define REG_CYLNO_LO    0x0e
56 #define REG_TLUN        0x0f
57 #define REG_CMD_PHASE   0x10
58 #define REG_SYN         0x11
59 #define REG_TCH         0x12
60 #define REG_TCM         0x13
61 #define REG_TCL         0x14
62 #define REG_DST_ID      0x15
63 #define REG_SRC_ID      0x16
64 #define REG_SCSI_STATUS 0x17    // (r)
65 #define REG_CMD         0x18
66 #define REG_DATA        0x19
67 #define REG_QUEUE_TAG   0x1a
68 #define REG_AUX_STATUS  0x1f    // (r)
69 
70 #define REG_CDBSIZE     0x00
71 #define REG_CDB1        0x03
72 #define REG_CDB2        0x04
73 #define REG_CDB3        0x05
74 #define REG_CDB4        0x06
75 #define REG_CDB5        0x07
76 #define REG_CDB6        0x08
77 #define REG_CDB7        0x09
78 #define REG_CDB8        0x0a
79 #define REG_CDB9        0x0b
80 #define REG_CDB10       0x0c
81 #define REG_CDB11       0x0d
82 #define REG_CDB12       0x0e
83 
84 #define OWN_EAF         0x08    // ENABLE ADVANCED FEATURES
85 
86 // SCSI STATUS
87 #define SS_RESET        0x00    // reset
88 #define SS_RESET_ADV    0x01    // reset w/adv. features
89 #define SS_XFER_END     0x16    // select and transfer complete
90 #define SS_SEL_TIMEOUT  0x42    // selection timeout
91 #define SS_DISCONNECT   0x85
92 
93 // AUX STATUS
94 #define AS_DBR          0x01    // data buffer ready
95 #define AS_CIP          0x10    // command in progress, chip is busy
96 #define AS_BSY          0x20    // Level 2 command in progress
97 #define AS_LCI          0x40    // last command ignored
98 #define AS_INT          0x80
99 
100 /*
101 #define MCI_IO          0x01
102 #define MCI_CD          0x02
103 #define MCI_MSG         0x04
104 #define MCI_COMMAND     MCI_CD
105 #define MCI_DATAIN      MCI_IO
106 #define MCI_DATAOUT     0
107 #define MCI_STATUS      (MCI_CD  | MCI_IO)
108 #define MCI_MSGIN       (MCI_MSG | MCI_CD | MCI_IO)
109 #define MCI_MSGOUT      (MCI_MSG | MCI_CD)
110 */
111 
112 /* command phase
113 0x00    NO_SELECT
114 0x10    SELECTED
115 0x20    IDENTIFY_SENT
116 0x30    COMMAND_OUT
117 0x41    SAVE_DATA_RECEIVED
118 0x42    DISCONNECT_RECEIVED
119 0x43    LEGAL_DISCONNECT
120 0x44    RESELECTED
121 0x45    IDENTIFY_RECEIVED
122 0x46    DATA_TRANSFER_DONE
123 0x47    STATUS_STARTED
124 0x50    STATUS_RECEIVED
125 0x60    COMPLETE_RECEIVED
126 */
127 
128 #define TARGET  wd33c93->dev[wd33c93->targetId]
129 
130 struct WD33C93
131 {
132     int         myId;
133     int         targetId;
134     UInt8       latch;
135     UInt8       regs[32];
136     SCSIDEVICE* dev[8];
137     int         maxDev;
138     SCSI_PHASE  phase;
139     //SCSI_PHASE  nextPhase;
140     //BoardTimer* timer;
141     //UInt32    timeout;
142     //int       timerRunning;
143     int         counter;
144     int         blockCounter;
145     int         tc;
146     int         devBusy;
147     int         hdId;
148     UInt8*      pBuf;
149     UInt8*      buffer;
150 };
151 
152 static FILE* scsiLog = NULL;
153 
wd33c93Disconnect(WD33C93 * wd33c93)154 static void wd33c93Disconnect(WD33C93* wd33c93)
155 {
156     if (wd33c93->phase != BusFree) {
157         if ((wd33c93->targetId >= 0) && (wd33c93->targetId < wd33c93->maxDev)) {
158             scsiDeviceDisconnect(TARGET);
159         }
160         if (wd33c93->regs[REG_SCSI_STATUS] != SS_XFER_END) {
161             wd33c93->regs[REG_SCSI_STATUS] = SS_DISCONNECT;
162         }
163         wd33c93->regs[REG_AUX_STATUS]  = AS_INT;
164         wd33c93->phase          = BusFree;
165         //wd33c93->nextPhase    = -1;
166     }
167 
168     //wd33c93->mci          = -1;
169     wd33c93->tc             = 0;
170     //wd33c93->atn          = 0;
171 
172     SCSILOG("busfree()\n\n");
173     scsiDeviceLogFlush();
174 }
175 
176 /*
177 static void wd33c93Irq(WD33C93* wd33c93, UInt32 time)
178 {
179     //wd33c93->timerRunning = 0;
180 
181     // set IRQ flag
182     wd33c93->regs[REG_AUX_STATUS] = AS_DBR | AS_INT;
183     // clear busy flags
184     wd33c93->regs[REG_AUX_STATUS] &= ~(AS_CIP | AS_BSY);
185 
186     // select w/ATN and transfer
187     wd33c93->regs[REG_SCSI_STATUS] = SS_XFER_END;
188     wd33c93->regs[REG_CMD_PHASE] = 0x60; // command successfully completed
189 
190     //setInt();
191 }
192 */
193 
wd33c93XferCb(WD33C93 * wd33c93,int length)194 static void wd33c93XferCb(WD33C93* wd33c93, int length)
195 {
196     wd33c93->devBusy = 0;
197 }
198 
wd33c93ExecCmd(WD33C93 * wd33c93,UInt8 value)199 static void wd33c93ExecCmd(WD33C93* wd33c93, UInt8 value)
200 {
201     int atn = 0;
202 
203     if (wd33c93->regs[REG_AUX_STATUS] & AS_CIP) {
204         SCSILOG("wd33c93ExecCmd() CIP error\n");
205         return;
206     }
207     //wd33c93->regs[REG_AUX_STATUS] |= AS_CIP;
208     wd33c93->regs[REG_CMD] = value;
209     switch (value) {
210     case 0x00: /* Reset controller (software reset) */
211         SCSILOG("wd33c93 [CMD] Reset controller\n");
212         memset(wd33c93->regs + 1, 0, 0x1a);
213         wd33c93Disconnect(wd33c93);
214         wd33c93->latch  = 0;
215         wd33c93->regs[REG_SCSI_STATUS] =
216             (wd33c93->regs[REG_OWN_ID] & OWN_EAF) ? SS_RESET_ADV : SS_RESET;
217         break;
218 
219     case 0x02:  /* Assert ATN */
220         SCSILOG("wd33c93 [CMD] Assert ATN\n");
221         break;
222 
223     case 0x04:  /* Disconnect */
224         SCSILOG("wd33c93 [CMD] Disconnect\n");
225         wd33c93Disconnect(wd33c93);
226         break;
227 
228     case 0x06:  /* Select with ATN (Lv2) */
229         atn = 1;
230     case 0x07:  /* Select Without ATN (Lv2) */
231         SCSILOG1("wd33c93 [CMD] Select (ATN %d)\n", atn);
232         wd33c93->targetId = wd33c93->regs[REG_DST_ID] & 7;
233         wd33c93->regs[REG_SCSI_STATUS] = SS_SEL_TIMEOUT;
234         wd33c93->tc = 0;
235         wd33c93->regs[REG_AUX_STATUS] = AS_INT;
236         break;
237 
238     case 0x08:  /* Select with ATN and transfer (Lv2) */
239         atn = 1;
240     case 0x09:  /* Select without ATN and Transfer (Lv2) */
241         SCSILOG1("wd33c93 [CMD] Select and transfer (ATN %d)\n", atn);
242         wd33c93->targetId = wd33c93->regs[REG_DST_ID] & 7;
243 
244         if (!wd33c93->devBusy &&
245             wd33c93->targetId < wd33c93->maxDev &&
246             /* wd33c93->targetId != wd33c93->myId  && */
247             scsiDeviceSelection(TARGET)) {
248             if (atn) scsiDeviceMsgOut(TARGET, wd33c93->regs[REG_TLUN] | 0x80);
249             wd33c93->devBusy = 1;
250             wd33c93->counter = scsiDeviceExecuteCmd(
251                             TARGET, &wd33c93->regs[REG_CDB1],
252                             &wd33c93->phase, &wd33c93->blockCounter);
253 
254             switch (wd33c93->phase) {
255             case Status:
256                 wd33c93->devBusy = 0;
257                 wd33c93->regs[REG_TLUN] = scsiDeviceGetStatusCode(TARGET);
258                 scsiDeviceMsgIn(TARGET);
259                 wd33c93->regs[REG_SCSI_STATUS] = SS_XFER_END;
260                 wd33c93Disconnect(wd33c93);
261                 break;
262 
263             case Execute:
264                 wd33c93->regs[REG_AUX_STATUS]  = AS_CIP | AS_BSY;
265                 wd33c93->pBuf = wd33c93->buffer;
266                 break;
267 
268             default:
269                 wd33c93->devBusy = 0;
270                 wd33c93->regs[REG_AUX_STATUS]  = AS_CIP | AS_BSY | AS_DBR;
271                 wd33c93->pBuf = wd33c93->buffer;
272             }
273             //wd33c93->regs[REG_SRC_ID] |= wd33c93->regs[REG_DST_ID] & 7;
274         } else {
275             //wd33c93->timeout = boardSystemTime() + boardFrequency() / 16384;
276             //wd33c93->timerRunning = 1;
277             //boardTimerAdd(wd33c93->timer, wd33c93->timeout);
278             SCSILOG1("wd33c93 %d timeout\n", wd33c93->targetId);
279             wd33c93->tc = 0;
280             wd33c93->regs[REG_SCSI_STATUS]  = SS_SEL_TIMEOUT;
281             wd33c93->regs[REG_AUX_STATUS]   = AS_INT;
282         }
283         break;
284 
285     case 0x18:  /* Translate Address (Lv2) */
286     default:
287         SCSILOG1("wd33c93 [CMD] unsupport command %x\n", value);
288         break;
289     }
290 }
wd33c93WriteAdr(WD33C93 * wd33c93,UInt16 port,UInt8 value)291 void wd33c93WriteAdr(WD33C93* wd33c93, UInt16 port, UInt8 value)
292 {
293     wd33c93->latch = value & 0x1f;
294 }
295 
wd33c93WriteCtrl(WD33C93 * wd33c93,UInt16 port,UInt8 value)296 void wd33c93WriteCtrl(WD33C93* wd33c93, UInt16 port, UInt8 value)
297 {
298     //SCSILOG2("wd33c93 write #%X, %X\n", wd33c93->latch, value);
299     switch (wd33c93->latch) {
300     case REG_OWN_ID:
301         wd33c93->regs[REG_OWN_ID] = value;
302         wd33c93->myId = value & 7;
303         SCSILOG1("wd33c93 myid = %X\n", wd33c93->myId);
304         break;
305 
306     case REG_TCH:
307         wd33c93->tc = (wd33c93->tc & 0x0000ffff) + (value << 16);
308         break;
309 
310     case REG_TCM:
311         wd33c93->tc = (wd33c93->tc & 0x00ff00ff) + (value << 8);
312         break;
313 
314     case REG_TCL:
315         wd33c93->tc = (wd33c93->tc & 0x00ffff00) + value;
316         break;
317 
318     case REG_CMD_PHASE:
319         SCSILOG1("wd33c93 CMD_PHASE = %X\n", value);
320         wd33c93->regs[REG_CMD_PHASE] = value;
321         break;
322 
323     case REG_CMD:
324         wd33c93ExecCmd(wd33c93, value);
325         return;
326 
327     case REG_DATA:
328         wd33c93->regs[REG_DATA] = value;
329         if (wd33c93->phase == DataOut) {
330             *wd33c93->pBuf++ = value;
331             --wd33c93->tc;
332             if (--wd33c93->counter == 0) {
333                 wd33c93->counter = scsiDeviceDataOut(TARGET, &wd33c93->blockCounter);
334                 if (wd33c93->counter) {
335                     wd33c93->pBuf = wd33c93->buffer;
336                     return;
337                 }
338                 wd33c93->regs[REG_TLUN] = scsiDeviceGetStatusCode(TARGET);
339                 scsiDeviceMsgIn(TARGET);
340                 wd33c93->regs[REG_SCSI_STATUS] = SS_XFER_END;
341                 wd33c93Disconnect(wd33c93);
342             }
343         }
344         return;
345 
346     case REG_AUX_STATUS:
347         return;
348 
349     default:
350         if (wd33c93->latch <= REG_SRC_ID) {
351             wd33c93->regs[wd33c93->latch] = value;
352         }
353         break;
354     }
355     wd33c93->latch++;
356     wd33c93->latch &= 0x1f;
357 }
358 
wd33c93ReadAuxStatus(WD33C93 * wd33c93,UInt16 port)359 UInt8 wd33c93ReadAuxStatus(WD33C93* wd33c93, UInt16 port)
360 {
361     UInt8 rv = wd33c93->regs[REG_AUX_STATUS];
362 
363     if (wd33c93->phase == Execute) {
364         wd33c93->counter =
365           scsiDeviceExecutingCmd(TARGET, &wd33c93->phase, &wd33c93->blockCounter);
366 
367         switch (wd33c93->phase) {
368         case Status:
369             wd33c93->regs[REG_TLUN] = scsiDeviceGetStatusCode(TARGET);
370             scsiDeviceMsgIn(TARGET);
371             wd33c93->regs[REG_SCSI_STATUS] = SS_XFER_END;
372             wd33c93Disconnect(wd33c93);
373             break;
374 
375         case Execute:
376             break;
377 
378         default:
379             wd33c93->regs[REG_AUX_STATUS] |= AS_DBR;
380         }
381     }
382 
383     return rv;
384 }
385 
wd33c93ReadCtrl(WD33C93 * wd33c93,UInt16 port)386 UInt8 wd33c93ReadCtrl(WD33C93* wd33c93, UInt16 port)
387 {
388     UInt8 rv;
389 
390     switch (wd33c93->latch) {
391     case REG_SCSI_STATUS:
392         rv = wd33c93->regs[REG_SCSI_STATUS];
393         //SCSILOG1("wd33c93 SCSI_STATUS = %X\n", rv);
394         if (rv != SS_XFER_END) {
395             wd33c93->regs[REG_AUX_STATUS] &= ~AS_INT;
396         } else {
397             wd33c93->regs[REG_SCSI_STATUS] = SS_DISCONNECT;
398             wd33c93->regs[REG_AUX_STATUS]  = AS_INT;
399         }
400         break;
401 
402     case REG_DATA:
403         if (wd33c93->phase == DataIn) {
404             rv = *wd33c93->pBuf++;
405             wd33c93->regs[REG_DATA] = rv;
406             --wd33c93->tc;
407             if (--wd33c93->counter == 0) {
408                 if (wd33c93->blockCounter > 0) {
409                     wd33c93->counter = scsiDeviceDataIn(TARGET, &wd33c93->blockCounter);
410                     if (wd33c93->counter) {
411                         wd33c93->pBuf = wd33c93->buffer;
412                         return rv;
413                     }
414                 }
415                 wd33c93->regs[REG_TLUN] = scsiDeviceGetStatusCode(TARGET);
416                 scsiDeviceMsgIn(TARGET);
417                 wd33c93->regs[REG_SCSI_STATUS] = SS_XFER_END;
418                 wd33c93Disconnect(wd33c93);
419             }
420         } else {
421             rv = wd33c93->regs[REG_DATA];
422         }
423         return rv;
424 
425     case REG_TCH:
426         rv = (UInt8)((wd33c93->tc >> 16) & 0xff);
427         break;
428 
429     case REG_TCM:
430         rv = (UInt8)((wd33c93->tc >> 8) & 0xff);
431         break;
432 
433     case REG_TCL:
434         rv = (UInt8)(wd33c93->tc & 0xff);
435         break;
436 
437     case REG_AUX_STATUS:
438         return wd33c93ReadAuxStatus(wd33c93, port);
439 
440     default:
441         rv = wd33c93->regs[wd33c93->latch];
442         break;
443     }
444     //SCSILOG2("wd33c93 read #%X, %X\n", wd33c93->latch, rv);
445 
446     if (wd33c93->latch != REG_CMD) {
447             wd33c93->latch++;
448             wd33c93->latch &= 0x1f;
449     }
450     return rv;
451 }
452 
wd33c93Peek(WD33C93 * wd33c93,UInt16 port)453 UInt8 wd33c93Peek(WD33C93* wd33c93, UInt16 port)
454 {
455     UInt8 rv;
456 
457     port &= 1;
458     if (port == 0) {
459         rv = wd33c93->regs[REG_AUX_STATUS];
460     } else {
461         switch (wd33c93->latch) {
462         case REG_TCH:
463             rv = (UInt8)((wd33c93->tc >> 16) & 0xff);
464             break;
465         case REG_TCM:
466             rv = (UInt8)((wd33c93->tc >> 8) & 0xff);
467             break;
468         case REG_TCL:
469             rv = (UInt8)(wd33c93->tc & 0xff);
470             break;
471         default:
472             rv = wd33c93->regs[wd33c93->latch];
473             break;
474         }
475     }
476     return rv;
477 }
478 
wd33c93Reset(WD33C93 * wd33c93,int scsireset)479 void wd33c93Reset(WD33C93* wd33c93, int scsireset)
480 {
481     int i;
482 
483     SCSILOG("wd33c93 reset\n");
484     scsiDeviceLogFlush();
485 
486     // initialized register
487     memset(wd33c93->regs, 0, 0x1b);
488     memset(wd33c93->regs + 0x1b, 0xff, 4);
489     wd33c93->regs[REG_AUX_STATUS] = AS_INT;
490     wd33c93->myId   = 0;
491     wd33c93->latch  = 0;
492     wd33c93->tc     = 0;
493     wd33c93->phase  = BusFree;
494     wd33c93->pBuf   = wd33c93->buffer;
495     if (scsireset) {
496         for (i = 0; i < wd33c93->maxDev; ++i) {
497             scsiDeviceReset(wd33c93->dev[i]);
498         }
499     }
500 }
501 
wd33c93Destroy(WD33C93 * wd33c93)502 void  wd33c93Destroy(WD33C93* wd33c93)
503 {
504     int i;
505 
506     for (i = 0; i < 8; ++i) {
507         if (wd33c93->dev[i]) scsiDeviceDestroy(wd33c93->dev[i]);
508     }
509 
510     //boardTimerDestroy(wd33c93->timer);
511 
512     SCSILOG("WD33C93 destroy\n");
513     scsiDeviceLogClose();
514 
515     archCdromBufferFree(wd33c93->buffer);
516     free(wd33c93);
517 }
518 
wd33c93ScsiDevCreate(WD33C93 * wd33c93,int id)519 static SCSIDEVICE* wd33c93ScsiDevCreate(WD33C93* wd33c93, int id)
520 {
521 #if 1
522     // CD_UPDATE: Use dynamic parameters instead of hard coded ones
523     int diskId, mode, type;
524 
525     diskId = diskGetHdDriveId(wd33c93->hdId, id);
526     if (diskIsCdrom(diskId)) {
527         mode = MODE_SCSI1 | MODE_UNITATTENTION | MODE_REMOVABLE | MODE_NOVAXIS;
528         type = SDT_CDROM;
529     } else {
530         mode = MODE_SCSI1 | MODE_UNITATTENTION | MODE_FDS120 | MODE_REMOVABLE | MODE_NOVAXIS;
531         type = SDT_DirectAccess;
532     }
533     return scsiDeviceCreate(id, diskId, wd33c93->buffer, NULL, type, mode,
534                            (CdromXferCompCb)wd33c93XferCb, wd33c93);
535 #else
536     SCSIDEVICE* dev;
537     int mode;
538     int type;
539 
540     if (id != 2) {
541         mode = MODE_SCSI1 | MODE_UNITATTENTION | MODE_FDS120 | MODE_REMOVABLE | MODE_NOVAXIS;
542         type = SDT_DirectAccess;
543     } else {
544         mode = MODE_SCSI1 | MODE_UNITATTENTION | MODE_REMOVABLE | MODE_NOVAXIS;
545         type = SDT_CDROM;
546     }
547     dev = scsiDeviceCreate(id, diskGetHdDriveId(wd33c93->hdId, id),
548             wd33c93->buffer, NULL, type, mode, (CdromXferCompCb)wd33c93XferCb, wd33c93);
549     return dev;
550 #endif
551 }
552 
wd33c93Create(int hdId)553 WD33C93* wd33c93Create(int hdId)
554 {
555     WD33C93* wd33c93 = malloc(sizeof(WD33C93));
556     int i;
557 
558     scsiLog = scsiDeviceLogCreate();
559     wd33c93->buffer  = archCdromBufferMalloc(BUFFER_SIZE);
560     wd33c93->maxDev  = 8;
561     wd33c93->hdId    = hdId;
562     wd33c93->devBusy = 0;
563     //wd33c93->timer = boardTimerCreate(wd33c93Irq, wd33c93);
564 
565     memset(wd33c93->dev, 0, sizeof(wd33c93->dev));
566     for (i = 0; i < wd33c93->maxDev; ++i) {
567         wd33c93->dev[i] = wd33c93ScsiDevCreate(wd33c93, i);
568     }
569 
570     wd33c93Reset(wd33c93, 0);
571 
572     return wd33c93;
573 }
574 
wd33c93SaveState(WD33C93 * wd33c93)575 void  wd33c93SaveState(WD33C93* wd33c93)
576 {
577     SaveState* state = saveStateOpenForWrite("wd33c93");
578     int i;
579 
580     saveStateSet(state, "myId",         wd33c93->myId);
581     saveStateSet(state, "targetId",     wd33c93->targetId);
582     saveStateSet(state, "latch",        wd33c93->latch);
583     saveStateSet(state, "phase",        wd33c93->phase);
584     saveStateSet(state, "counter",      wd33c93->counter);
585     saveStateSet(state, "blockCounter", wd33c93->blockCounter);
586     saveStateSet(state, "tc",           wd33c93->tc);
587     saveStateSet(state, "maxDev",       wd33c93->maxDev);
588     saveStateSet(state, "pBuf",         wd33c93->pBuf - wd33c93->buffer);
589     //saveStateGet(state, "timeout",    wd33c93->timeout);
590     //saveStateGet(state, "timerRunning", wd33c93->timerRunning);
591 
592     saveStateSetBuffer(state, "regs",   wd33c93->regs,   sizeof(wd33c93->regs));
593     saveStateSetBuffer(state, "buffer", wd33c93->buffer, BUFFER_SIZE);
594 
595     saveStateClose(state);
596 
597     for (i = 0; i < wd33c93->maxDev; ++i) {
598         scsiDeviceSaveState(wd33c93->dev[i]);
599     }
600 }
601 
wd33c93LoadState(WD33C93 * wd33c93)602 void  wd33c93LoadState(WD33C93* wd33c93)
603 {
604     SaveState* state = saveStateOpenForRead("wd33c93");
605     int old = wd33c93->maxDev;
606     int i;
607 
608     wd33c93->myId         =        saveStateGet(state, "myId",          0);
609     wd33c93->targetId     =        saveStateGet(state, "targetId",      0);
610     wd33c93->latch        = (UInt8)saveStateGet(state, "latch",         0);
611     wd33c93->phase        =        saveStateGet(state, "phase",         BusFree);
612     wd33c93->counter      =        saveStateGet(state, "counter",       0);
613     wd33c93->blockCounter =        saveStateGet(state, "blockCounter",  0);
614     wd33c93->tc           =        saveStateGet(state, "tc",            0);
615     wd33c93->maxDev       =        saveStateGet(state, "maxDev",        8);
616     wd33c93->pBuf         =        saveStateGet(state, "pBuf",          0) + wd33c93->buffer;
617     //wd33c93->timeout    =        saveStateGet(state, "timeout",       0);
618     //wd33c93->timerRunning =      saveStateGet(state, "timerRunning",  0);
619 
620     saveStateGetBuffer(state, "regs",   wd33c93->regs,   sizeof(wd33c93->regs));
621     saveStateGetBuffer(state, "buffer", wd33c93->buffer, BUFFER_SIZE);
622 
623     saveStateClose(state);
624 
625     if (old < wd33c93->maxDev) {
626         for (i = old; i < wd33c93->maxDev; ++i) {
627             wd33c93->dev[i] = wd33c93ScsiDevCreate(wd33c93, i);
628         }
629     }
630 
631     for (i = 0; i < wd33c93->maxDev; ++i) {
632         scsiDeviceLoadState(wd33c93->dev[i]);
633     }
634 /*
635     if (wd33c93->timerRunning) {
636         boardTimerAdd(wd33c93->timer, wd33c93->timeout);
637     }
638 */
639 }
640