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