openMSX
MB89352.cc
Go to the documentation of this file.
1 /* Ported from:
2 ** Source: /cvsroot/bluemsx/blueMSX/Src/IoDevice/MB89352.c,v
3 ** Revision: 1.9
4 ** Date: 2007/03/28 17:35:35
5 **
6 ** More info: http://www.bluemsx.com
7 **
8 ** Copyright (C) 2003-2007 Daniel Vik, white cat
9 */
10 /*
11  * Notes:
12  * Not suppport padding transfer and interrupt signal. (Not used MEGA-SCSI)
13  * Message system might be imperfect. (Not used in MEGA-SCSI usually)
14  */
15 #include "MB89352.hh"
16 #include "SCSIDevice.hh"
17 #include "DummySCSIDevice.hh"
18 #include "SCSIHD.hh"
19 #include "SCSILS120.hh"
20 #include "DeviceConfig.hh"
21 #include "XMLElement.hh"
22 #include "MSXException.hh"
23 #include "serialize.hh"
24 #include <cassert>
25 #include <string>
26 #include <cstring>
27 #include <memory>
28 
29 using std::string;
30 
31 namespace openmsx {
32 
33 static const byte REG_BDID = 0; // Bus Device ID (r/w)
34 static const byte REG_SCTL = 1; // Spc Control (r/w)
35 static const byte REG_SCMD = 2; // Command (r/w)
36 static const byte REG_OPEN = 3; // (open)
37 static const byte REG_INTS = 4; // Interrupt Sense (r/w)
38 static const byte REG_PSNS = 5; // Phase Sense (r)
39 static const byte REG_SDGC = 5; // SPC Diag. Control (w)
40 static const byte REG_SSTS = 6; // SPC SCSI::STATUS (r)
41 static const byte REG_SERR = 7; // SPC Error SCSI::STATUS (r/w?)
42 static const byte REG_PCTL = 8; // Phase Control (r/w)
43 static const byte REG_MBC = 9; // Modified Byte Counter(r)
44 static const byte REG_DREG = 10; // Data Register (r/w)
45 static const byte REG_TEMP = 11; // Temporary Register (r/w)
46  // Another value is maintained respec-
47  // tively for writing and for reading
48 static const byte REG_TCH = 12; // Transfer Counter High(r/w)
49 static const byte REG_TCM = 13; // Transfer Counter Mid (r/w)
50 static const byte REG_TCL = 14; // Transfer Counter Low (r/w)
51 
52 static const byte REG_TEMPWR = 13; // (TEMP register preservation place for writing)
53 static const byte FIX_PCTL = 14; // (REG_PCTL & 7)
54 
55 static const byte PSNS_IO = 0x01;
56 static const byte PSNS_CD = 0x02;
57 static const byte PSNS_MSG = 0x04;
58 static const byte PSNS_BSY = 0x08;
59 static const byte PSNS_SEL = 0x10;
60 static const byte PSNS_ATN = 0x20;
61 static const byte PSNS_ACK = 0x40;
62 static const byte PSNS_REQ = 0x80;
63 
64 static const byte PSNS_SELECTION = PSNS_SEL;
65 static const byte PSNS_COMMAND = PSNS_CD;
66 static const byte PSNS_DATAIN = PSNS_IO;
67 static const byte PSNS_DATAOUT = 0;
68 static const byte PSNS_STATUS = PSNS_CD | PSNS_IO;
69 static const byte PSNS_MSGIN = PSNS_MSG | PSNS_CD | PSNS_IO;
70 static const byte PSNS_MSGOUT = PSNS_MSG | PSNS_CD;
71 
72 static const byte INTS_ResetCondition = 0x01;
73 static const byte INTS_SPC_HardError = 0x02;
74 static const byte INTS_TimeOut = 0x04;
75 static const byte INTS_ServiceRequited = 0x08;
76 static const byte INTS_CommandComplete = 0x10;
77 static const byte INTS_Disconnected = 0x20;
78 static const byte INTS_ReSelected = 0x40;
79 static const byte INTS_Selected = 0x80;
80 
81 static const byte CMD_BusRelease = 0x00;
82 static const byte CMD_Select = 0x20;
83 static const byte CMD_ResetATN = 0x40;
84 static const byte CMD_SetATN = 0x60;
85 static const byte CMD_Transfer = 0x80;
86 static const byte CMD_TransferPause = 0xA0;
87 static const byte CMD_Reset_ACK_REQ = 0xC0;
88 static const byte CMD_Set_ACK_REQ = 0xE0;
89 static const byte CMD_MASK = 0xE0;
90 
91 static const unsigned MAX_DEV = 8;
92 
94 {
95  // TODO: devBusy = false;
96 
97  // ALMOST COPY PASTED FROM WD33C93:
98 
99  for (auto* t : config.getXML()->getChildren("target")) {
100  unsigned id = t->getAttributeAsInt("id");
101  if (id >= MAX_DEV) {
102  throw MSXException(
103  "Invalid SCSI id: ", id,
104  " (should be 0..", MAX_DEV - 1, ')');
105  }
106  if (dev[id]) {
107  throw MSXException("Duplicate SCSI id: ", id);
108  }
109  DeviceConfig conf(config, *t);
110  auto& type = t->getChild("type").getData();
111  if (type == "SCSIHD") {
112  dev[id] = std::make_unique<SCSIHD>(conf, buffer,
114  } else if (type == "SCSILS120") {
115  dev[id] = std::make_unique<SCSILS120>(conf, buffer,
117  } else {
118  throw MSXException("Unknown SCSI device: ", type);
119  }
120  }
121  // fill remaining targets with dummy SCSI devices to prevent crashes
122  for (auto& d : dev) {
123  if (!d) d = std::make_unique<DummySCSIDevice>();
124  }
125  reset(false);
126 
127  // avoid UMR on savestate
128  memset(buffer.data(), 0, SCSIDevice::BUFFER_SIZE);
129  msgin = 0;
130  blockCounter = 0;
131  nextPhase = SCSI::UNDEFINED;
132  targetId = 0;
133 }
134 
135 void MB89352::disconnect()
136 {
137  if (phase != SCSI::BUS_FREE) {
138  assert(targetId < MAX_DEV);
139  dev[targetId]->disconnect();
140  regs[REG_INTS] |= INTS_Disconnected;
141  phase = SCSI::BUS_FREE;
142  nextPhase = SCSI::UNDEFINED;
143  }
144 
145  regs[REG_PSNS] = 0;
146  isBusy = false;
147  isTransfer = false;
148  counter = 0;
149  tc = 0;
150  atn = 0;
151 }
152 
153 void MB89352::softReset()
154 {
155  isEnabled = false;
156 
157  for (int i = 2; i < 15; ++i) {
158  regs[i] = 0;
159  }
160  regs[15] = 0xFF; // un mapped
161  memset(cdb, 0, sizeof(cdb));
162 
163  cdbIdx = 0;
164  bufIdx = 0;
165  phase = SCSI::BUS_FREE;
166  disconnect();
167 }
168 
169 void MB89352::reset(bool scsireset)
170 {
171  regs[REG_BDID] = 0x80; // Initial value
172  regs[REG_SCTL] = 0x80;
173  rst = false;
174  atn = 0;
175  myId = 7;
176 
177  softReset();
178 
179  if (scsireset) {
180  for (auto& d : dev) {
181  d->reset();
182  }
183  }
184 }
185 
186 void MB89352::setACKREQ(byte& value)
187 {
188  // REQ check
189  if ((regs[REG_PSNS] & (PSNS_REQ | PSNS_BSY)) != (PSNS_REQ | PSNS_BSY)) {
190  // set ACK/REQ: REQ/BSY check error
191  if (regs[REG_PSNS] & PSNS_IO) { // SCSI -> SPC
192  value = 0xFF;
193  }
194  return;
195  }
196 
197  // phase check
198  if (regs[FIX_PCTL] != (regs[REG_PSNS] & 7)) {
199  // set ACK/REQ: phase check error
200  if (regs[REG_PSNS] & PSNS_IO) { // SCSI -> SPC
201  value = 0xFF;
202  }
203  if (isTransfer) {
204  regs[REG_INTS] |= INTS_ServiceRequited;
205  }
206  return;
207  }
208 
209  switch (phase) {
210  case SCSI::DATA_IN: // Transfer phase (data in)
211  value = buffer[bufIdx];
212  ++bufIdx;
213  regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_DATAIN;
214  break;
215 
216  case SCSI::DATA_OUT: // Transfer phase (data out)
217  buffer[bufIdx] = value;
218  ++bufIdx;
219  regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_DATAOUT;
220  break;
221 
222  case SCSI::COMMAND: // Command phase
223  if (counter < 0) {
224  // Initialize command routine
225  cdbIdx = 0;
226  counter = (value < 0x20) ? 6 : ((value < 0xA0) ? 10 : 12);
227  }
228  cdb[cdbIdx] = value;
229  ++cdbIdx;
230  regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_COMMAND;
231  break;
232 
233  case SCSI::STATUS: // SCSI::STATUS phase
234  value = dev[targetId]->getStatusCode();
235  regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_STATUS;
236  break;
237 
238  case SCSI::MSG_IN: // Message In phase
239  value = dev[targetId]->msgIn();
240  regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_MSGIN;
241  break;
242 
243  case SCSI::MSG_OUT: // Message Out phase
244  msgin |= dev[targetId]->msgOut(value);
245  regs[REG_PSNS] = PSNS_ACK | PSNS_BSY | PSNS_MSGOUT;
246  break;
247 
248  default:
249  // set ACK/REQ code error
250  break;
251  }
252 }
253 
254 void MB89352::resetACKREQ()
255 {
256  // ACK check
257  if ((regs[REG_PSNS] & (PSNS_ACK | PSNS_BSY)) != (PSNS_ACK | PSNS_BSY)) {
258  // reset ACK/REQ: ACK/BSY check error
259  return;
260  }
261 
262  // phase check
263  if (regs[FIX_PCTL] != (regs[REG_PSNS] & 7)) {
264  // reset ACK/REQ: phase check error
265  if (isTransfer) {
266  regs[REG_INTS] |= INTS_ServiceRequited;
267  }
268  return;
269  }
270 
271  switch (phase) {
272  case SCSI::DATA_IN: // Transfer phase (data in)
273  if (--counter > 0) {
274  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
275  } else {
276  if (blockCounter > 0) {
277  counter = dev[targetId]->dataIn(blockCounter);
278  if (counter) {
279  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
280  bufIdx = 0;
281  break;
282  }
283  }
284  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
285  phase = SCSI::STATUS;
286  }
287  break;
288 
289  case SCSI::DATA_OUT: // Transfer phase (data out)
290  if (--counter > 0) {
291  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
292  } else {
293  counter = dev[targetId]->dataOut(blockCounter);
294  if (counter) {
295  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
296  bufIdx = 0;
297  break;
298  }
299  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
300  phase = SCSI::STATUS;
301  }
302  break;
303 
304  case SCSI::COMMAND: // Command phase
305  if (--counter > 0) {
306  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
307  } else {
308  bufIdx = 0; // reset buffer index
309  // TODO: devBusy = true;
310  counter = dev[targetId]->executeCmd(cdb, phase, blockCounter);
311  switch (phase) {
312  case SCSI::DATA_IN:
313  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
314  break;
315  case SCSI::DATA_OUT:
316  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
317  break;
318  case SCSI::STATUS:
319  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
320  break;
321  case SCSI::EXECUTE:
322  regs[REG_PSNS] = PSNS_BSY;
323  return; // note: return iso break
324  default:
325  // phase error
326  break;
327  }
328  // TODO: devBusy = false;
329  }
330  break;
331 
332  case SCSI::STATUS: // SCSI::STATUS phase
333  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGIN;
334  phase = SCSI::MSG_IN;
335  break;
336 
337  case SCSI::MSG_IN: // Message In phase
338  if (msgin <= 0) {
339  disconnect();
340  break;
341  }
342  msgin = 0;
343  // fall-through
344  case SCSI::MSG_OUT: // Message Out phase
345  if (msgin == -1) {
346  disconnect();
347  return;
348  }
349 
350  if (atn) {
351  if (msgin & 2) {
352  disconnect();
353  return;
354  }
355  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
356  return;
357  }
358 
359  if (msgin & 1) {
360  phase = SCSI::MSG_IN;
361  } else {
362  if (msgin & 4) {
363  phase = SCSI::STATUS;
364  nextPhase = SCSI::UNDEFINED;
365  } else {
366  phase = nextPhase;
367  nextPhase = SCSI::UNDEFINED;
368  }
369  }
370 
371  msgin = 0;
372 
373  switch (phase) {
374  case SCSI::COMMAND:
375  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
376  break;
377  case SCSI::DATA_IN:
378  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
379  break;
380  case SCSI::DATA_OUT:
381  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
382  break;
383  case SCSI::STATUS:
384  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
385  break;
386  case SCSI::MSG_IN:
387  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGIN;
388  break;
389  default:
390  // MsgOut code error
391  break;
392  }
393  return;
394 
395  default:
396  //UNREACHABLE;
397  // reset ACK/REQ code error
398  break;
399  }
400 
401  if (atn) {
402  nextPhase = phase;
403  phase = SCSI::MSG_OUT;
404  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
405  }
406 }
407 
409 {
410  if (isTransfer && (tc > 0)) {
411  setACKREQ(regs[REG_DREG]);
412  resetACKREQ();
413 
414  --tc;
415  if (tc == 0) {
416  isTransfer = false;
417  regs[REG_INTS] |= INTS_CommandComplete;
418  }
419  regs[REG_MBC] = (regs[REG_MBC] - 1) & 0x0F;
420  return regs[REG_DREG];
421  } else {
422  return 0xFF;
423  }
424 }
425 
427 {
428  if (isTransfer && (tc > 0)) {
429  setACKREQ(value);
430  resetACKREQ();
431 
432  --tc;
433  if (tc == 0) {
434  isTransfer = false;
435  regs[REG_INTS] |= INTS_CommandComplete;
436  }
437  regs[REG_MBC] = (regs[REG_MBC] - 1) & 0x0F;
438  }
439 }
440 
442 {
443  switch (reg) {
444  case REG_DREG: // write data Register
445  writeDREG(value);
446  break;
447 
448  case REG_SCMD: {
449  if (!isEnabled) {
450  break;
451  }
452 
453  // bus reset
454  if (value & 0x10) {
455  if (((regs[REG_SCMD] & 0x10) == 0) & (regs[REG_SCTL] == 0)) {
456  rst = true;
457  regs[REG_INTS] |= INTS_ResetCondition;
458  for (auto& d : dev) {
459  d->busReset();
460  }
461  disconnect(); // alternative routine
462  }
463  } else {
464  rst = false;
465  }
466 
467  regs[REG_SCMD] = value;
468 
469  // execute spc command
470  switch (value & CMD_MASK) {
471  case CMD_Set_ACK_REQ:
472  switch (phase) {
473  case SCSI::DATA_IN:
474  case SCSI::STATUS:
475  case SCSI::MSG_IN:
476  setACKREQ(regs[REG_TEMP]);
477  break;
478  default:
479  setACKREQ(regs[REG_TEMPWR]);
480  }
481  break;
482 
483  case CMD_Reset_ACK_REQ:
484  resetACKREQ();
485  break;
486 
487  case CMD_Select: {
488  if (rst) {
489  regs[REG_INTS] |= INTS_TimeOut;
490  break;
491  }
492 
493  if (regs[REG_PCTL] & 1) {
494  // reselection error
495  regs[REG_INTS] |= INTS_TimeOut;
496  disconnect();
497  break;
498  }
499  bool err = false;
500  int x = regs[REG_BDID] & regs[REG_TEMPWR];
501  if (phase == SCSI::BUS_FREE && x && x != regs[REG_TEMPWR]) {
502  x = regs[REG_TEMPWR] & ~regs[REG_BDID];
503  assert(x != 0); // because of the check 2 lines above
504 
505  // the targetID is calculated.
506  // It is given priority that the number is large.
507  targetId = 0;
508  while (true) {
509  x >>= 1;
510  if (x == 0) break;
511  ++targetId;
512  assert(targetId < MAX_DEV);
513  }
514 
515  if ( dev[targetId]->isSelected()) {
516  // target selection OK
517  regs[REG_INTS] |= INTS_CommandComplete;
518  isBusy = true;
519  msgin = 0;
520  counter = -1;
521  err = false;
522  if (atn) {
523  phase = SCSI::MSG_OUT;
524  nextPhase = SCSI::COMMAND;
525  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
526  } else {
527  phase = SCSI::COMMAND;
528  nextPhase = SCSI::UNDEFINED;
529  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_COMMAND;
530  }
531  } else {
532  err = true;
533  }
534  } else {
535  err = true;
536  }
537 
538  if (err) {
539  // target selection error
540  regs[REG_INTS] |= INTS_TimeOut;
541  disconnect();
542  }
543  break;
544  }
545  // hardware transfer
546  case CMD_Transfer:
547  if ((regs[FIX_PCTL] == (regs[REG_PSNS] & 7)) &&
548  (regs[REG_PSNS] & (PSNS_REQ | PSNS_BSY))) {
549  isTransfer = true; // set Xfer in Progress
550  } else {
551  // phase error
552  regs[REG_INTS] |= INTS_ServiceRequited;
553  }
554  break;
555 
556  case CMD_BusRelease:
557  disconnect();
558  break;
559 
560  case CMD_SetATN:
561  atn = PSNS_ATN;
562  break;
563 
564  case CMD_ResetATN:
565  atn = 0;
566  break;
567 
568  case CMD_TransferPause:
569  // nothing is done in the initiator.
570  break;
571  }
572  break; // end of REG_SCMD
573  }
574  case REG_INTS: // Reset Interrupts
575  regs[REG_INTS] &= ~value;
576  if (rst) {
577  regs[REG_INTS] |= INTS_ResetCondition;
578  }
579  break;
580 
581  case REG_TEMP:
582  regs[REG_TEMPWR] = value;
583  break;
584 
585  case REG_TCL:
586  tc = (tc & 0xFFFF00) + (value << 0);
587  break;
588 
589  case REG_TCM:
590  tc = (tc & 0xFF00FF) + (value << 8);
591  break;
592 
593  case REG_TCH:
594  tc = (tc & 0x00FFFF) + (value << 16);
595  break;
596 
597  case REG_PCTL:
598  regs[REG_PCTL] = value;
599  regs[FIX_PCTL] = value & 7;
600  break;
601 
602  case REG_BDID:
603  // set Bus Device ID
604  value &= 7;
605  myId = value;
606  regs[REG_BDID] = 1 << value;
607  break;
608 
609  // Nothing
610  case REG_SDGC:
611  case REG_SSTS:
612  case REG_SERR:
613  case REG_MBC:
614  case 15:
615  break;
616 
617  case REG_SCTL: {
618  bool flag = !(value & 0xE0);
619  if (flag != isEnabled) {
620  isEnabled = flag;
621  if (!flag) {
622  softReset();
623  }
624  }
625  }
626  // fall-through
627  default:
628  regs[reg] = value;
629  }
630 }
631 
632 byte MB89352::getSSTS() const
633 {
634  byte result = 1; // set fifo empty
635  if (isTransfer) {
636  if (regs[REG_PSNS] & PSNS_IO) { // SCSI -> SPC transfer
637  if (tc >= 8) {
638  result = 2; // set fifo full
639  } else {
640  if (tc != 0) {
641  result = 0; // set fifo 1..7 bytes
642  }
643  }
644  }
645  }
646  if (phase != SCSI::BUS_FREE) {
647  result |= 0x80; // set iniciator
648  }
649  if (isBusy) {
650  result |= 0x20; // set SPC_BSY
651  }
652  if ((phase >= SCSI::COMMAND) || isTransfer) {
653  result |= 0x10; // set Xfer in Progress
654  }
655  if (rst) {
656  result |= 0x08; // set SCSI RST
657  }
658  if (tc == 0) {
659  result |= 0x04; // set tc = 0
660  }
661  return result;
662 }
663 
665 {
666  switch (reg) {
667  case REG_DREG:
668  return readDREG();
669 
670  case REG_PSNS:
671  if (phase == SCSI::EXECUTE) {
672  counter = dev[targetId]->executingCmd(phase, blockCounter);
673  if (atn && phase != SCSI::EXECUTE) {
674  nextPhase = phase;
675  phase = SCSI::MSG_OUT;
676  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_MSGOUT;
677  } else {
678  switch (phase) {
679  case SCSI::DATA_IN:
680  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAIN;
681  break;
682  case SCSI::DATA_OUT:
683  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_DATAOUT;
684  break;
685  case SCSI::STATUS:
686  regs[REG_PSNS] = PSNS_REQ | PSNS_BSY | PSNS_STATUS;
687  break;
688  case SCSI::EXECUTE:
689  regs[REG_PSNS] = PSNS_BSY;
690  break;
691  default:
692  // phase error
693  break;
694  }
695  }
696  }
697  return regs[REG_PSNS] | atn;
698 
699  default:
700  return peekRegister(reg);
701  }
702 }
703 
705 {
706  if (isTransfer && (tc > 0)) {
707  return regs[REG_DREG];
708  } else {
709  return 0xFF;
710  }
711 }
712 
714 {
715  switch (reg) {
716  case REG_DREG:
717  return peekDREG();
718  case REG_PSNS:
719  return regs[REG_PSNS] | atn;
720  case REG_SSTS:
721  return getSSTS();
722  case REG_TCH:
723  return (tc >> 16) & 0xFF;
724  case REG_TCM:
725  return (tc >> 8) & 0xFF;
726  case REG_TCL:
727  return (tc >> 0) & 0xFF;
728  default:
729  return regs[reg];
730  }
731 }
732 
733 
734 // TODO duplicated in WD33C93.cc
735 static std::initializer_list<enum_string<SCSI::Phase>> phaseInfo = {
736  { "UNDEFINED", SCSI::UNDEFINED },
737  { "BUS_FREE", SCSI::BUS_FREE },
738  { "ARBITRATION", SCSI::ARBITRATION },
739  { "SELECTION", SCSI::SELECTION },
740  { "RESELECTION", SCSI::RESELECTION },
741  { "COMMAND", SCSI::COMMAND },
742  { "EXECUTE", SCSI::EXECUTE },
743  { "DATA_IN", SCSI::DATA_IN },
744  { "DATA_OUT", SCSI::DATA_OUT },
745  { "STATUS", SCSI::STATUS },
746  { "MSG_OUT", SCSI::MSG_OUT },
747  { "MSG_IN", SCSI::MSG_IN }
748 };
749 SERIALIZE_ENUM(SCSI::Phase, phaseInfo);
750 
751 template<typename Archive>
752 void MB89352::serialize(Archive& ar, unsigned /*version*/)
753 {
754  ar.serialize_blob("buffer", buffer.data(), buffer.size());
755  char tag[8] = { 'd', 'e', 'v', 'i', 'c', 'e', 'X', 0 };
756  for (unsigned i = 0; i < MAX_DEV; ++i) {
757  tag[6] = char('0' + i);
758  ar.serializePolymorphic(tag, *dev[i]);
759  }
760  ar.serialize("bufIdx", bufIdx);
761  ar.serialize("msgin", msgin);
762  ar.serialize("counter", counter);
763  ar.serialize("blockCounter", blockCounter);
764  ar.serialize("tc", tc);
765  ar.serialize("phase", phase);
766  ar.serialize("nextPhase", nextPhase);
767  ar.serialize("myId", myId);
768  ar.serialize("targetId", targetId);
769  ar.serialize_blob("registers", regs, sizeof(regs));
770  ar.serialize("rst", rst);
771  ar.serialize("atn", atn);
772  ar.serialize("isEnabled", isEnabled);
773  ar.serialize("isBusy", isBusy);
774  ar.serialize("isTransfer", isTransfer);
775  ar.serialize("cdbIdx", cdbIdx);
776  ar.serialize_blob("cdb", cdb, sizeof(cdb));
777 }
779 
780 } // namespace openmsx
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
void serialize(Archive &ar, unsigned version)
Definition: MB89352.cc:752
byte readDREG()
Definition: MB89352.cc:408
uint8_t byte
8 bit unsigned integer
Definition: openmsx.hh:26
void writeDREG(byte value)
Definition: MB89352.cc:426
static const unsigned MODE_SCSI2
Definition: SCSIDevice.hh:16
void writeRegister(byte reg, byte value)
Definition: MB89352.cc:441
static const unsigned BUFFER_SIZE
Definition: SCSIDevice.hh:23
byte peekRegister(byte reg) const
Definition: MB89352.cc:713
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:840
const XMLElement * getXML() const
Definition: DeviceConfig.hh:47
void reset(bool scsireset)
Definition: MB89352.cc:169
static const unsigned MODE_MEGASCSI
Definition: SCSIDevice.hh:19
MB89352(const DeviceConfig &config)
Definition: MB89352.cc:93
byte peekDREG() const
Definition: MB89352.cc:704
const Children & getChildren() const
Definition: XMLElement.hh:47
TclObject t
byte readRegister(byte reg)
Definition: MB89352.cc:664