1 /******************************************************************************/
2 /* Mednafen Sony PS1 Emulation Module                                         */
3 /******************************************************************************/
4 /* cdc.cpp:
5 **  Copyright (C) 2011-2018 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 // TODO: Test seekl to CD-DA, and seekl to beyond end of disc.
23 
24 // TODO: Rewrite command processing to use switch() state machine madness, to handle some commands(like 0x0A) whose timing
25 //       characteristics cannot be handled well with the current way.  Be sure to test interruptability(with a new command) of the commands, too.
26 
27 #pragma GCC optimize ("unroll-loops")
28 
29 /*
30   Games to test after changing code affecting CD reading and buffering:
31 	Bedlam (massive graphics corruption)
32 	Rise 2 (massive graphics corruption)
33 
34 	Captain Commando (boss graphics corruption on first stage)
35 	Gran Turismo (missing music; GetLocL must be valid and sector data must be ready simultaneous with clearing of status seek bit and setting of reading bit)
36 	Harukanaru Toki no Naka de - Banjou Yuugi (needs GetLocL to reflect dancing around target seek position after seek completes; otherwise hangs on voice acting)
37 	Incredible Crisis (needs GetLocL to be valid after a SeekL; otherwise hangs without music near start of "Etsuko and the Golden Pig")
38 	Tomb Raider(needs GetLocP to reflect dancing around target seek position after seek completes; otherwise, CD-DA tracks at M:S:F=x:x:0 fail to play and game hangs)
39 	Vib Ribbon, with extra audio CD
40 	Mortal Kombat Trilogy, music resumption after pause.
41 
42   Nightmare Creatures hangs during startup for some CD timing alignments/windows, and it spams command 0x0A without properly waiting for it to complete.
43 */
44 
45 // TODO: async command counter and async command phase?
46 /*
47 
48  TODO:
49 	Implement missing commands.
50 
51 	SPU CD-DA and CD-XA streaming semantics.
52 */
53 
54 /*
55  After eject(doesn't appear to occur when drive is in STOP state):
56 	* Does not appear to occur in STOP state.
57 	* Does not appear to occur in PAUSE state.
58 	* DOES appear to occur in STANDBY state. (TODO: retest)
59 
60 % Result 0: 16
61 % Result 1: 08
62 % IRQ Result: e5
63 % 19 e0
64 
65  Command abortion tests(NOP tested):
66 	Does not appear to occur when in STOP or PAUSE states(STOP or PAUSE command just executed).
67 
68 	DOES occur after a ReadTOC completes, if ReadTOC is not followed by a STOP or PAUSE.  Odd.
69 */
70 
71 #include "psx.h"
72 #include "cdc.h"
73 #include "spu.h"
74 
75 using namespace CDUtility;
76 
77 namespace MDFN_IEN_PSX
78 {
79 
PS_CDC()80 PS_CDC::PS_CDC() : DMABuffer(4096)
81 {
82  IsPSXDisc = false;
83  Cur_CDIF = NULL;
84 
85  DriveStatus = DS_STOPPED;
86  PendingCommandPhase = 0;
87 }
88 
~PS_CDC()89 PS_CDC::~PS_CDC()
90 {
91 
92 }
93 
SetDisc(bool tray_open,CDInterface * cdif,const char * disc_id)94 void PS_CDC::SetDisc(bool tray_open, CDInterface* cdif, const char *disc_id)
95 {
96  if(tray_open)
97   cdif = NULL;
98 
99  Cur_CDIF = cdif;
100  IsPSXDisc = false;
101  memset(DiscID, 0, sizeof(DiscID));
102 
103  if(Cur_CDIF)
104  {
105   HeaderBufValid = false;
106   DiscStartupDelay = (int64)1000 * 33868800 / 1000;
107   DiscChanged = true;
108 
109   Cur_CDIF->ReadTOC(&toc);
110 
111   if(disc_id)
112   {
113    strncpy((char *)DiscID, disc_id, 4);
114    IsPSXDisc = true;
115   }
116  }
117 }
118 
CalcNextEvent(void)119 int32 PS_CDC::CalcNextEvent(void)
120 {
121  int32 next_event = SPUCounter;
122 
123  if(PSRCounter > 0 && next_event > PSRCounter)
124   next_event = PSRCounter;
125 
126  if(PendingCommandCounter > 0 && next_event > PendingCommandCounter)
127   next_event = PendingCommandCounter;
128 
129  if(!(IRQBuffer & 0xF))
130  {
131   if(CDCReadyReceiveCounter > 0 && next_event > CDCReadyReceiveCounter)
132    next_event = CDCReadyReceiveCounter;
133  }
134 
135  if(DiscStartupDelay > 0 && next_event > DiscStartupDelay)
136   next_event = DiscStartupDelay;
137 
138  //fprintf(stderr, "%d %d %d %d --- %d\n", PSRCounter, PendingCommandCounter, CDCReadyReceiveCounter, DiscStartupDelay, next_event);
139 
140  return(next_event);
141 }
142 
SoftReset(void)143 void PS_CDC::SoftReset(void)
144 {
145  ClearAudioBuffers();
146 
147  // Not sure about initial volume state
148  Pending_DecodeVolume[0][0] = 0x80;
149  Pending_DecodeVolume[0][1] = 0x00;
150  Pending_DecodeVolume[1][0] = 0x00;
151  Pending_DecodeVolume[1][1] = 0x80;
152  memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));
153 
154  RegSelector = 0;
155  memset(ArgsBuf, 0, sizeof(ArgsBuf));
156  ArgsWP = ArgsRP = 0;
157 
158  memset(ResultsBuffer, 0, sizeof(ResultsBuffer));
159  ResultsWP = 0;
160  ResultsRP = 0;
161  ResultsIn = 0;
162 
163  CDCReadyReceiveCounter = 0;
164 
165  IRQBuffer = 0;
166  IRQOutTestMask = 0;
167  RecalcIRQ();
168 
169  DMABuffer.Flush();
170  SB_In = 0;
171  SectorPipe_Pos = SectorPipe_In = 0;
172  SectorsRead = 0;
173 
174  memset(SubQBuf, 0, sizeof(SubQBuf));
175  memset(SubQBuf_Safe, 0, sizeof(SubQBuf_Safe));
176  SubQChecksumOK = false;
177 
178  memset(HeaderBuf, 0, sizeof(HeaderBuf));
179 
180 
181  FilterFile = 0;
182  FilterChan = 0;
183 
184  PendingCommand = 0;
185  PendingCommandPhase = 0;
186  PendingCommandCounter = 0;
187 
188  Mode = 0x20;
189 
190  HeaderBufValid = false;
191  SeekFinished = -1;
192  DriveStatus = DS_STOPPED;
193  ClearAIP();
194  StatusAfterSeek = DS_STOPPED;
195  SeekRetryCounter = 0;
196 
197  Forward = false;
198  Backward = false;
199  Muted = false;
200 
201  PlayTrackMatch = 0;
202 
203  PSRCounter = 0;
204 
205  CurSector = 0;
206 
207  ClearAIP();
208 
209  SeekTarget = 0;
210 
211  CommandLoc = 0;
212  CommandLoc_Dirty = true;
213 
214  DiscChanged = true;
215 }
216 
Power(void)217 void PS_CDC::Power(void)
218 {
219  SPU->Power();
220 
221  SoftReset();
222 
223  HoldLogicalPos = false;
224 
225  DiscStartupDelay = 0;
226 
227  SPUCounter = SPU->UpdateFromCDC(0);
228  lastts = 0;
229 }
230 
StateAction(StateMem * sm,const unsigned load,const bool data_only)231 void PS_CDC::StateAction(StateMem *sm, const unsigned load, const bool data_only)
232 {
233  SFORMAT StateRegs[] =
234  {
235   SFVAR(DiscChanged),
236   SFVAR(DiscStartupDelay),
237 
238   SFVARN(AudioBuffer.Samples, "&AudioBuffer.Samples[0][0]"),
239   SFVAR(AudioBuffer.Size),
240   SFVAR(AudioBuffer.Freq),
241   SFVAR(AudioBuffer.ReadPos),
242 
243   SFVARN(Pending_DecodeVolume, "&Pending_DecodeVolume[0][0]"),
244   SFVARN(DecodeVolume, "&DecodeVolume[0][0]"),
245 
246   SFVARN(ADPCM_ResampBuf, "&ADPCM_ResampBuf[0][0]"),
247   SFVAR(ADPCM_ResampCurPhase),
248   SFVAR(ADPCM_ResampCurPos),
249 
250 
251 
252   SFVAR(RegSelector),
253   SFVAR(ArgsBuf),
254   SFVAR(ArgsWP),
255   SFVAR(ArgsRP),
256 
257   SFVAR(ArgsReceiveLatch),
258   SFVAR(ArgsReceiveBuf),
259   SFVAR(ArgsReceiveIn),
260 
261   SFVAR(ResultsBuffer),
262   SFVAR(ResultsIn),
263   SFVAR(ResultsWP),
264   SFVAR(ResultsRP),
265 
266   //
267   //
268   //
269   SFPTR8(&DMABuffer.data[0], DMABuffer.data.size()),
270   SFVAR(DMABuffer.read_pos),
271   SFVAR(DMABuffer.write_pos),
272   SFVAR(DMABuffer.in_count),
273   //
274   //
275   //
276 
277   SFVAR(SB),
278   SFVAR(SB_In),
279 
280   SFVARN(SectorPipe, "&SectorPipe[0][0]"),
281   SFVAR(SectorPipe_Pos),
282   SFVAR(SectorPipe_In),
283 
284   SFVAR(SubQBuf),
285   SFVAR(SubQBuf_Safe),
286 
287   SFVAR(SubQChecksumOK),
288 
289   SFVAR(HeaderBufValid),
290   SFVAR(HeaderBuf),
291 
292   SFVAR(IRQBuffer),
293   SFVAR(IRQOutTestMask),
294   SFVAR(CDCReadyReceiveCounter),
295 
296 
297   SFVAR(FilterFile),
298   SFVAR(FilterChan),
299 
300   SFVAR(PendingCommand),
301   SFVAR(PendingCommandPhase),
302   SFVAR(PendingCommandCounter),
303 
304   SFVAR(SPUCounter),
305 
306   SFVAR(Mode),
307   SFVAR(DriveStatus),
308   SFVAR(StatusAfterSeek),
309   SFVAR(Forward),
310   SFVAR(Backward),
311   SFVAR(Muted),
312 
313   SFVAR(PlayTrackMatch),
314 
315   SFVAR(PSRCounter),
316 
317   SFVAR(HoldLogicalPos),
318 
319   SFVAR(CurSector),
320   SFVAR(SectorsRead),
321 
322   SFVAR(AsyncIRQPending),
323   SFVAR(AsyncResultsPending),
324   SFVAR(AsyncResultsPendingCount),
325 
326   SFVAR(SeekTarget),
327   SFVAR(SeekRetryCounter),
328   SFVAR(SeekFinished),
329 
330  // FIXME: Save TOC stuff?
331 #if 0
332  CDUtility::TOC toc;
333  bool IsPSXDisc;
334  uint8 DiscID[4];
335 #endif
336 
337   SFVAR(CommandLoc),
338   SFVAR(CommandLoc_Dirty),
339   SFVARN(xa_previous, "&xa_previous[0][0]"),
340 
341   SFVAR(xa_cur_set),
342   SFVAR(xa_cur_file),
343   SFVAR(xa_cur_chan),
344 
345   SFVAR(ReportLastF),
346   SFVAR(ReportStartupDelay),
347 
348   SFEND
349  };
350 
351  MDFNSS_StateAction(sm, load, data_only, StateRegs, "CDC");
352 
353  if(load)
354  {
355   DMABuffer.SaveStatePostLoad();
356   SectorPipe_Pos %= SectorPipe_Count;
357 
358   if(AudioBuffer.Size > sizeof(AudioBuffer.Samples[0]) / sizeof(AudioBuffer.Samples[0][0]))
359    AudioBuffer.Size = sizeof(AudioBuffer.Samples[0]) / sizeof(AudioBuffer.Samples[0][0]);
360 
361   if(AudioBuffer.ReadPos > AudioBuffer.Size)
362    AudioBuffer.ReadPos = AudioBuffer.Size;
363 
364   ResultsRP &= 0xF;
365   ResultsWP &= 0xF;
366   ResultsIn &= 0x1F;
367 
368   ADPCM_ResampCurPos &= 0x1F;
369   ADPCM_ResampCurPhase %= 7;
370  }
371 }
372 
ResetTS(void)373 void PS_CDC::ResetTS(void)
374 {
375  lastts = 0;
376 }
377 
RecalcIRQ(void)378 void PS_CDC::RecalcIRQ(void)
379 {
380  IRQ_Assert(IRQ_CD, (bool)(IRQBuffer & (IRQOutTestMask & 0x1F)));
381 }
382 
383 //static int32 doom_ts;
WriteIRQ(uint8 V)384 void PS_CDC::WriteIRQ(uint8 V)
385 {
386  assert(CDCReadyReceiveCounter <= 0);
387  assert(!(IRQBuffer & 0xF));
388 
389  //PSX_WARNING("[CDC] ***IRQTHINGY: 0x%02x -- %u", V, doom_ts);
390 
391  CDCReadyReceiveCounter = 2000; //1024;
392 
393  IRQBuffer = (IRQBuffer & 0x10) | V;
394  RecalcIRQ();
395 }
396 
BeginResults(void)397 void PS_CDC::BeginResults(void)
398 {
399  //if(ResultsIn)
400  // {
401  // printf("Cleared %d results. IRQBuffer=0x%02x\n", ResultsIn, IRQBuffer);
402  //}
403 
404  ResultsIn = 0;
405  ResultsWP = 0;
406  ResultsRP = 0;
407 
408  memset(ResultsBuffer, 0x00, sizeof(ResultsBuffer));
409 }
410 
WriteResult(uint8 V)411 void PS_CDC::WriteResult(uint8 V)
412 {
413  ResultsBuffer[ResultsWP] = V;
414  ResultsWP = (ResultsWP + 1) & 0xF;
415  ResultsIn = (ResultsIn + 1) & 0x1F;
416 
417  if(!ResultsIn)
418   PSX_WARNING("[CDC] Results buffer overflow!");
419 }
420 
ReadResult(void)421 uint8 PS_CDC::ReadResult(void)
422 {
423  uint8 ret = ResultsBuffer[ResultsRP];
424 
425  if(!ResultsIn)
426   PSX_WARNING("[CDC] Results buffer underflow!");
427 
428  ResultsRP = (ResultsRP + 1) & 0xF;
429  ResultsIn = (ResultsIn - 1) & 0x1F;
430 
431  return ret;
432 }
433 
MakeStatus(bool cmd_error)434 uint8 PS_CDC::MakeStatus(bool cmd_error)
435 {
436  uint8 ret = 0;
437 
438  // Are these bit positions right?
439 
440  if(DriveStatus == DS_PLAYING)
441   ret |= 0x80;
442 
443  if(DriveStatus == DS_READING)
444   ret |= 0x20;
445 
446  if(DriveStatus == DS_SEEKING || DriveStatus == DS_SEEKING_LOGICAL || DriveStatus == DS_SEEKING_LOGICAL2)
447   ret |= 0x40;
448 
449  if(!Cur_CDIF || DiscChanged)
450   ret |= 0x10;
451 
452  if(DriveStatus != DS_STOPPED)
453   ret |= 0x02;
454 
455  if(cmd_error)
456   ret |= 0x01;
457 
458  DiscChanged = false;	// FIXME: Only do it on NOP command execution?
459 
460  return(ret);
461 }
462 
DecodeSubQ(uint8 * subpw)463 bool PS_CDC::DecodeSubQ(uint8 *subpw)
464 {
465  uint8 tmp_q[0xC];
466 
467  memset(tmp_q, 0, 0xC);
468 
469  for(int i = 0; i < 96; i++)
470   tmp_q[i >> 3] |= ((subpw[i] & 0x40) >> 6) << (7 - (i & 7));
471 
472  if((tmp_q[0] & 0xF) == 1)
473  {
474   memcpy(SubQBuf, tmp_q, 0xC);
475   SubQChecksumOK = subq_check_checksum(tmp_q);
476 
477   if(SubQChecksumOK)
478   {
479    memcpy(SubQBuf_Safe, tmp_q, 0xC);
480    return(true);
481   }
482  }
483 
484  return(false);
485 }
486 
487 static const int16 CDADPCMImpulse[7][25] =
488 {
489  {     0,    -5,    17,   -35,    70,   -23,   -68,   347,  -839,  2062, -4681, 15367, 21472, -5882,  2810, -1352,   635,  -235,    26,    43,   -35,    16,    -8,     2,     0,  }, /* 0 */
490  {     0,    -2,    10,   -34,    65,   -84,    52,     9,  -266,  1024, -2680,  9036, 26516, -6016,  3021, -1571,   848,  -365,   107,    10,   -16,    17,    -8,     3,    -1,  }, /* 1 */
491  {    -2,     0,     3,   -19,    60,   -75,   162,  -227,   306,   -67,  -615,  3229, 29883, -4532,  2488, -1471,   882,  -424,   166,   -27,     5,     6,    -8,     3,    -1,  }, /* 2 */
492  {    -1,     3,    -2,    -5,    31,   -74,   179,  -402,   689,  -926,  1272, -1446, 31033, -1446,  1272,  -926,   689,  -402,   179,   -74,    31,    -5,    -2,     3,    -1,  }, /* 3 */
493  {    -1,     3,    -8,     6,     5,   -27,   166,  -424,   882, -1471,  2488, -4532, 29883,  3229,  -615,   -67,   306,  -227,   162,   -75,    60,   -19,     3,     0,    -2,  }, /* 4 */
494  {    -1,     3,    -8,    17,   -16,    10,   107,  -365,   848, -1571,  3021, -6016, 26516,  9036, -2680,  1024,  -266,     9,    52,   -84,    65,   -34,    10,    -2,     0,  }, /* 5 */
495  {     0,     2,    -8,    16,   -35,    43,    26,  -235,   635, -1352,  2810, -5882, 21472, 15367, -4681,  2062,  -839,   347,   -68,   -23,    70,   -35,    17,    -5,     0,  }, /* 6 */
496 };
497 
ReadAudioBuffer(int32 samples[2])498 void PS_CDC::ReadAudioBuffer(int32 samples[2])
499 {
500  samples[0] = AudioBuffer.Samples[0][AudioBuffer.ReadPos];
501  samples[1] = AudioBuffer.Samples[1][AudioBuffer.ReadPos];
502 
503  AudioBuffer.ReadPos++;
504 }
505 
ApplyVolume(int32 samples[2])506 INLINE void PS_CDC::ApplyVolume(int32 samples[2])
507 {
508  //
509  // Take care not to alter samples[] before we're done calculating the new output samples!
510  //
511  int32 left_out = ((samples[0] * DecodeVolume[0][0]) >> 7) + ((samples[1] * DecodeVolume[1][0]) >> 7);
512  int32 right_out = ((samples[0] * DecodeVolume[0][1]) >> 7) + ((samples[1] * DecodeVolume[1][1]) >> 7);
513 
514  clamp(&left_out, -32768, 32767);
515  clamp(&right_out, -32768, 32767);
516 
517  if(Muted)
518  {
519   left_out = 0;
520   right_out = 0;
521  }
522 
523  samples[0] = left_out;
524  samples[1] = right_out;
525 }
526 
527 //
528 // This function must always set samples[0] and samples[1], even if just to 0; range of samples[n] shall be restricted to -32768 through 32767.
529 //
GetCDAudio(int32 samples[2])530 void PS_CDC::GetCDAudio(int32 samples[2])
531 {
532  const unsigned freq = (AudioBuffer.ReadPos < AudioBuffer.Size) ? AudioBuffer.Freq : 0;
533 
534  samples[0] = 0;
535  samples[1] = 0;
536 
537  if(!freq)
538   return;
539 
540  if(freq == 7 || freq == 14)
541  {
542   ReadAudioBuffer(samples);
543   if(freq == 14)
544    ReadAudioBuffer(samples);
545  }
546  else
547  {
548   int32 out_tmp[2] = { 0, 0 };
549 
550   for(unsigned i = 0; i < 2; i++)
551   {
552    const int16* imp = CDADPCMImpulse[ADPCM_ResampCurPhase];
553    int16* wf = &ADPCM_ResampBuf[i][(ADPCM_ResampCurPos + 32 - 25) & 0x1F];
554 
555    for(unsigned s = 0; s < 25; s++)
556    {
557     out_tmp[i] += imp[s] * wf[s];
558    }
559 
560    out_tmp[i] >>= 15;
561    clamp(&out_tmp[i], -32768, 32767);
562    samples[i] = out_tmp[i];
563   }
564 
565   ADPCM_ResampCurPhase += freq;
566 
567   if(ADPCM_ResampCurPhase >= 7)
568   {
569    int32 raw[2] = { 0, 0 };
570 
571    ADPCM_ResampCurPhase -= 7;
572    ReadAudioBuffer(raw);
573 
574    for(unsigned i = 0; i < 2; i++)
575    {
576     ADPCM_ResampBuf[i][ADPCM_ResampCurPos +  0] =
577     ADPCM_ResampBuf[i][ADPCM_ResampCurPos + 32] = raw[i];
578    }
579    ADPCM_ResampCurPos = (ADPCM_ResampCurPos + 1) & 0x1F;
580   }
581  }
582 
583  //
584  // Algorithmically, volume is applied after resampling for CD-XA ADPCM playback, per PS1 tests(though when "mute" is applied wasn't tested).
585  //
586  ApplyVolume(samples);
587 }
588 
589 
590 struct XA_Subheader
591 {
592  uint8 file;
593  uint8 channel;
594  uint8 submode;
595  uint8 coding;
596 
597  uint8 file_dup;
598  uint8 channel_dup;
599  uint8 submode_dup;
600  uint8 coding_dup;
601 };
602 static_assert(sizeof(XA_Subheader) == 8, "XA_Subheader wrong size!");
603 
604 struct XA_SoundGroup
605 {
606  uint8 params[16];
607  uint8 samples[112];
608 };
609 static_assert(sizeof(XA_SoundGroup) == 128, "XA_SoundGroup wrong size!");
610 
611 #define XA_SUBMODE_EOF		0x80
612 #define XA_SUBMODE_REALTIME	0x40
613 #define XA_SUBMODE_FORM		0x20
614 #define XA_SUBMODE_TRIGGER	0x10
615 #define XA_SUBMODE_DATA		0x08
616 #define XA_SUBMODE_AUDIO	0x04
617 #define XA_SUBMODE_VIDEO	0x02
618 #define XA_SUBMODE_EOR		0x01
619 
620 #define XA_CODING_EMPHASIS	0x40
621 
622 //#define XA_CODING_BPS_MASK	0x30
623 //#define XA_CODING_BPS_4BIT	0x00
624 //#define XA_CODING_BPS_8BIT	0x10
625 //#define XA_CODING_SR_MASK	0x0C
626 //#define XA_CODING_SR_378	0x00
627 //#define XA_CODING_SR_
628 
629 #define XA_CODING_8BIT		0x10
630 #define XA_CODING_189		0x04
631 #define XA_CODING_STEREO	0x01
632 
633 // Special regression prevention test cases:
634 //	Um Jammer Lammy (start doing poorly)
635 //	Yarudora Series Vol.1 - Double Cast (non-FMV speech)
636 
XA_Test(const uint8 * sdata)637 bool PS_CDC::XA_Test(const uint8 *sdata)
638 {
639  const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];
640 
641  if(!(Mode & MODE_STRSND))
642   return false;
643 
644  if(!(sh->submode & XA_SUBMODE_AUDIO))
645   return false;
646 
647  //printf("Test File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup);
648 
649  if((Mode & MODE_SF) && (sh->file != FilterFile || sh->channel != FilterChan))
650   return false;
651 
652  if(!xa_cur_set || (Mode & MODE_SF))
653  {
654   xa_cur_set = true;
655   xa_cur_file = sh->file;
656   xa_cur_chan = sh->channel;
657  }
658  else if(sh->file != xa_cur_file || sh->channel != xa_cur_chan)
659   return false;
660 
661  if(sh->submode & XA_SUBMODE_EOF)
662  {
663   //puts("YAY");
664   xa_cur_set = false;
665   xa_cur_file = 0;
666   xa_cur_chan = 0;
667  }
668 
669  return true;
670 }
671 
ClearAudioBuffers(void)672 void PS_CDC::ClearAudioBuffers(void)
673 {
674  memset(&AudioBuffer, 0, sizeof(AudioBuffer));
675  memset(xa_previous, 0, sizeof(xa_previous));
676 
677  xa_cur_set = false;
678  xa_cur_file = 0;
679  xa_cur_chan = 0;
680 
681  memset(ADPCM_ResampBuf, 0, sizeof(ADPCM_ResampBuf));
682  ADPCM_ResampCurPhase = 0;
683  ADPCM_ResampCurPos = 0;
684 }
685 
686 //
687 // output should be readable at -2 and -1
DecodeXAADPCM(const uint8 * input,int16 * output,const unsigned shift,const unsigned weight)688 static void DecodeXAADPCM(const uint8 *input, int16 *output, const unsigned shift, const unsigned weight)
689 {
690  // Weights copied over from SPU channel ADPCM playback code, may not be entirely the same for CD-XA ADPCM, we need to run tests.
691  static const int32 Weights[16][2] =
692  {
693   // s-1    s-2
694   {   0,    0 },
695   {  60,    0 },
696   { 115,  -52 },
697   {  98,  -55 },
698   { 122,  -60 },
699  };
700 
701  for(int i = 0; i < 28; i++)
702  {
703   int32 sample;
704 
705   sample = (int16)(input[i] << 8);
706   sample >>= shift;
707 
708   sample += ((output[i - 1] * Weights[weight][0]) >> 6) + ((output[i - 2] * Weights[weight][1]) >> 6);
709 
710   if(sample < -32768)
711    sample = -32768;
712 
713   if(sample > 32767)
714    sample = 32767;
715 
716   output[i] = sample;
717  }
718 }
719 
XA_ProcessSector(const uint8 * sdata,CD_Audio_Buffer * ab)720 void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab)
721 {
722  const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];
723  const unsigned unit_index_shift = (sh->coding & XA_CODING_8BIT) ? 0 : 1;
724 
725  //printf("File: 0x%02x 0x%02x - Channel: 0x%02x 0x%02x - Submode: 0x%02x 0x%02x - Coding: 0x%02x 0x%02x - \n", sh->file, sh->file_dup, sh->channel, sh->channel_dup, sh->submode, sh->submode_dup, sh->coding, sh->coding_dup);
726  ab->ReadPos = 0;
727  ab->Size = 18 * (4 << unit_index_shift) * 28;
728 
729  if(sh->coding & XA_CODING_STEREO)
730   ab->Size >>= 1;
731 
732  ab->Freq = (sh->coding & XA_CODING_189) ? 3 : 6;
733 
734  //fprintf(stderr, "Coding: %02x %02x\n", sh->coding, sh->coding_dup);
735 
736  for(unsigned group = 0; group < 18; group++)
737  {
738   const XA_SoundGroup *sg = (const XA_SoundGroup *)&sdata[12 + 4 + 8 + group * 128];
739 
740   for(unsigned unit = 0; unit < (4U << unit_index_shift); unit++)
741   {
742    const uint8 param = sg->params[(unit & 3) | ((unit & 4) << 1)];
743    const uint8 param_copy = sg->params[4 | (unit & 3) | ((unit & 4) << 1)];
744    uint8 ibuffer[28];
745    int16 obuffer[2 + 28];
746 
747    if(param != param_copy)
748    {
749     PSX_WARNING("[CDC] CD-XA param != param_copy --- %d %02x %02x\n", unit, param, param_copy);
750    }
751 
752    for(unsigned i = 0; i < 28; i++)
753    {
754     uint8 tmp = sg->samples[i * 4 + (unit >> unit_index_shift)];
755 
756     if(unit_index_shift)
757     {
758      tmp <<= (unit & 1) ? 0 : 4;
759      tmp &= 0xf0;
760     }
761 
762     ibuffer[i] = tmp;
763    }
764 
765    const bool ocn = (bool)(unit & 1) && (sh->coding & XA_CODING_STEREO);
766 
767    obuffer[0] = xa_previous[ocn][0];
768    obuffer[1] = xa_previous[ocn][1];
769 
770    DecodeXAADPCM(ibuffer, &obuffer[2], param & 0x0F, param >> 4);
771 
772    xa_previous[ocn][0] = obuffer[28];
773    xa_previous[ocn][1] = obuffer[29];
774 
775    if(param != param_copy)
776     memset(obuffer, 0, sizeof(obuffer));
777 
778    if(sh->coding & XA_CODING_STEREO)
779    {
780     for(unsigned s = 0; s < 28; s++)
781     {
782      ab->Samples[ocn][group * (2 << unit_index_shift) * 28 + (unit >> 1) * 28 + s] = obuffer[2 + s];
783     }
784    }
785    else
786    {
787     for(unsigned s = 0; s < 28; s++)
788     {
789      ab->Samples[0][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s];
790      ab->Samples[1][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s];
791     }
792    }
793   }
794  }
795 
796 #if 0
797  // Test
798  for(unsigned i = 0; i < ab->Size; i++)
799  {
800   static unsigned counter = 0;
801 
802   ab->Samples[0][i] = (counter & 2) ? -0x6000 : 0x6000;
803   ab->Samples[1][i] = rand();
804   counter++;
805  }
806 #endif
807 }
808 
ClearAIP(void)809 void PS_CDC::ClearAIP(void)
810 {
811  AsyncResultsPendingCount = 0;
812  AsyncIRQPending = 0;
813 }
814 
CheckAIP(void)815 void PS_CDC::CheckAIP(void)
816 {
817  if(AsyncIRQPending && CDCReadyReceiveCounter <= 0)
818  {
819   BeginResults();
820 
821   for(unsigned i = 0; i < AsyncResultsPendingCount; i++)
822    WriteResult(AsyncResultsPending[i]);
823 
824   WriteIRQ(AsyncIRQPending);
825 
826   ClearAIP();
827  }
828 }
829 
SetAIP(unsigned irq,unsigned result_count,uint8 * r)830 void PS_CDC::SetAIP(unsigned irq, unsigned result_count, uint8 *r)
831 {
832  if(AsyncIRQPending)
833  {
834   PSX_WARNING("***WARNING*** Previous notification skipped: CurSector=%d, old_notification=0x%02x", CurSector, AsyncIRQPending);
835  }
836  ClearAIP();
837 
838  AsyncResultsPendingCount = result_count;
839 
840  for(unsigned i = 0; i < result_count; i++)
841   AsyncResultsPending[i] = r[i];
842 
843  AsyncIRQPending = irq;
844 
845  CheckAIP();
846 }
847 
SetAIP(unsigned irq,uint8 result0)848 void PS_CDC::SetAIP(unsigned irq, uint8 result0)
849 {
850  uint8 tr[1] = { result0 };
851  SetAIP(irq, 1, tr);
852 }
853 
SetAIP(unsigned irq,uint8 result0,uint8 result1)854 void PS_CDC::SetAIP(unsigned irq, uint8 result0, uint8 result1)
855 {
856  uint8 tr[2] = { result0, result1 };
857  SetAIP(irq, 2, tr);
858 }
859 
860 
EnbufferizeCDDASector(const uint8 * buf)861 void PS_CDC::EnbufferizeCDDASector(const uint8 *buf)
862 {
863 	CD_Audio_Buffer *ab = &AudioBuffer;
864 
865         ab->Freq = 7 * ((Mode & MODE_SPEED) ? 2 : 1);
866         ab->Size = 588;
867 
868 	if(SubQBuf_Safe[0] & 0x40)
869 	{
870 	 for(int i = 0; i < 588; i++)
871 	 {
872 	  ab->Samples[0][i] = 0;
873 	  ab->Samples[1][i] = 0;
874 	 }
875 	}
876 	else
877 	{
878 	 for(int i = 0; i < 588; i++)
879 	 {
880 	  ab->Samples[0][i] = (int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 0]);
881 	  ab->Samples[1][i] = (int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 2]);
882 	 }
883 	}
884 
885 	ab->ReadPos = 0;
886 }
887 
HandlePlayRead(void)888 void PS_CDC::HandlePlayRead(void)
889 {
890  uint8 read_buf[2352 + 96];
891 
892  //PSX_WARNING("Read sector: %d", CurSector);
893 
894  if(CurSector >= ((int32)toc.tracks[100].lba + 300) && CurSector >= (75 * 60 * 75 - 150))
895  {
896   PSX_WARNING("[CDC] Read/Play position waaay too far out(%u), forcing STOP", CurSector);
897   SeekFinished = -1;
898   DriveStatus = DS_STOPPED;
899   SectorPipe_Pos = SectorPipe_In = 0;
900   SectorsRead = 0;
901   return;
902  }
903 
904  if(CurSector >= (int32)toc.tracks[100].lba)
905  {
906   PSX_WARNING("[CDC] In leadout area: %u", CurSector);
907  }
908 
909  Cur_CDIF->ReadRawSector(read_buf, CurSector);	// FIXME: error out on error.
910  DecodeSubQ(read_buf + 2352);
911 
912  if(SubQBuf_Safe[1] == 0xAA && (DriveStatus == DS_PLAYING || (DriveStatus == DS_READING && !(SubQBuf_Safe[0] & 0x40) && (Mode & MODE_CDDA))))
913  {
914   HeaderBufValid = false;
915 
916   PSX_WARNING("[CDC] CD-DA leadout reached: %u", CurSector);
917 
918   // Status in this end-of-disc context here should be generated after we're in the pause state.
919   SeekTarget = CurSector;
920   DriveStatus = DS_PAUSED;
921   SectorPipe_Pos = SectorPipe_In = 0;
922   SectorsRead = 0;
923   SetAIP(CDCIRQ_DATA_END, MakeStatus());
924 
925   return;
926  }
927 
928  if(DriveStatus == DS_PLAYING)
929  {
930   if(Mode & MODE_AUTOPAUSE)
931   {
932    // Note: Some game(s) start playing in the pregap of a track(so don't replace this with a simple subq index == 0 check for autopause).
933    // Pitball enables autopause a while after playing starts.
934    //
935    if(PlayTrackMatch == -1 && SubQChecksumOK)
936     PlayTrackMatch = SubQBuf_Safe[0x1];
937 
938    if(PlayTrackMatch != -1 && SubQBuf_Safe[0x1] != PlayTrackMatch)
939    {
940     // Status needs to be taken before we're paused(IE it should still report playing).
941     SetAIP(CDCIRQ_DATA_END, MakeStatus());
942 
943     SeekTarget = CurSector;
944     DriveStatus = DS_PAUSED;
945     SectorPipe_Pos = SectorPipe_In = 0;
946     SectorsRead = 0;
947     PSRCounter = 0;
948     return;
949    }
950   }
951 
952   if((Mode & MODE_REPORT) && ReportStartupDelay <= 0 && (((SubQBuf_Safe[0x9] >> 4) != ReportLastF) || Forward || Backward) && SubQChecksumOK)
953   {
954    uint8 tr[8];
955    uint16 abs_lev_max = 0;
956    bool abs_lev_chselect = SubQBuf_Safe[0x8] & 0x01;
957 
958    for(int i = 0; i < 588; i++)
959     abs_lev_max = std::max<uint16>(abs_lev_max, std::min<int>(abs((int16)MDFN_de16lsb(&read_buf[i * 4 + (abs_lev_chselect * 2)])), 32767));
960    abs_lev_max |= abs_lev_chselect << 15;
961 
962    tr[0] = MakeStatus();
963    tr[1] = SubQBuf_Safe[0x1];	// Track
964    tr[2] = SubQBuf_Safe[0x2];	// Index
965 
966    if(SubQBuf_Safe[0x9] & 0x10)
967    {
968     tr[3] = SubQBuf_Safe[0x3];		// R M
969     tr[4] = SubQBuf_Safe[0x4] | 0x80;	// R S
970     tr[5] = SubQBuf_Safe[0x5];		// R F
971    }
972    else
973    {
974     tr[3] = SubQBuf_Safe[0x7];	// A M
975     tr[4] = SubQBuf_Safe[0x8];	// A S
976     tr[5] = SubQBuf_Safe[0x9];	// A F
977    }
978 
979    tr[6] = abs_lev_max >> 0;
980    tr[7] = abs_lev_max >> 8;
981 
982    SetAIP(CDCIRQ_DATA_READY, 8, tr);
983   }
984   ReportLastF = SubQBuf_Safe[0x9] >> 4;
985  }
986 
987  if(SectorPipe_In >= SectorPipe_Count)
988  {
989   uint8* buf = SectorPipe[SectorPipe_Pos];
990   SectorPipe_In--;
991 
992   if(SubQBuf_Safe[0] & 0x40) // Data sector
993   {
994    if(DriveStatus == DS_SEEKING_LOGICAL2 || DriveStatus == DS_READING || (HoldLogicalPos && (DriveStatus == DS_PAUSED || DriveStatus == DS_STANDBY)))
995    {
996     memcpy(HeaderBuf, buf + 12, 12);
997     HeaderBufValid = true;
998 
999     if(DriveStatus == DS_SEEKING_LOGICAL2)
1000     {
1001      if(AMSF_to_LBA(BCD_to_U8(HeaderBuf[0]), BCD_to_U8(HeaderBuf[1]), BCD_to_U8(HeaderBuf[2])) == SeekTarget)
1002      {
1003       //puts("Logical2 seek finished");
1004       DriveStatus = StatusAfterSeek;
1005       SeekFinished = true;
1006       ReportStartupDelay = 24000000;
1007      }
1008      else
1009      {
1010       if(!SeekRetryCounter)
1011       {
1012        HoldLogicalPos = false;
1013        DriveStatus = DS_STANDBY;
1014        SeekFinished = -1;
1015       }
1016       else
1017        SeekRetryCounter--;
1018      }
1019     }
1020    }
1021    //
1022    //
1023    //
1024    //printf("%d, %02x:%02x:%02x --- %d %d\n", DriveStatus, HeaderBuf[0], HeaderBuf[1], HeaderBuf[2], SeekTarget, AMSF_to_LBA(BCD_to_U8(HeaderBuf[0]), BCD_to_U8(HeaderBuf[1]), BCD_to_U8(HeaderBuf[2])));
1025 
1026    if(DriveStatus == DS_READING)
1027    {
1028     if((Mode & MODE_STRSND) && (buf[12 + 3] == 0x2) && ((buf[12 + 6] & 0x64) == 0x64))
1029     {
1030      if(XA_Test(buf))
1031      {
1032       if(AudioBuffer.ReadPos < AudioBuffer.Size)
1033       {
1034        PSX_WARNING("[CDC] CD-XA ADPCM sector skipped - readpos=0x%04x, size=0x%04x", AudioBuffer.ReadPos, AudioBuffer.Size);
1035       }
1036       else
1037       {
1038        XA_ProcessSector(buf, &AudioBuffer);
1039       }
1040      }
1041     }
1042     else
1043     {
1044      // maybe if(!(Mode & 0x30)) too?
1045      if(!(buf[12 + 6] & 0x20))
1046      {
1047       if(!edc_lec_check_and_correct(buf, true))
1048       {
1049        MDFN_Notify(MDFN_NOTICE_WARNING, _("Uncorrectable error(s) in sector %d."), CurSector);
1050       }
1051      }
1052 
1053      if(!(Mode & 0x30) && (buf[12 + 6] & 0x20))
1054       PSX_WARNING("[CDC] BORK: %d", CurSector);
1055 
1056      int32 offs = (Mode & 0x20) ? 0 : 12;
1057      int32 size = (Mode & 0x20) ? 2340 : 2048;
1058 
1059      if(Mode & 0x10)
1060      {
1061       offs = 12;
1062       size = 2328;
1063      }
1064 
1065      memcpy(SB, buf + 12 + offs, size);
1066      SB_In = size;
1067      SetAIP(CDCIRQ_DATA_READY, MakeStatus());
1068     }
1069    }
1070   }
1071   else // CD-DA sector
1072   {
1073    if(DriveStatus == DS_SEEKING_LOGICAL2)
1074    {
1075     if(Mode & MODE_CDDA)
1076     {
1077      DriveStatus = StatusAfterSeek;
1078      SeekFinished = true;
1079      ReportStartupDelay = 24000000;
1080     }
1081     else
1082     {
1083      if(!SeekRetryCounter)
1084      {
1085       HoldLogicalPos = false;
1086       DriveStatus = DS_STANDBY;
1087       SeekFinished = -1;
1088      }
1089      else
1090       SeekRetryCounter--;
1091     }
1092    }
1093    //
1094    //
1095    //
1096    if((DriveStatus == DS_READING && (Mode & MODE_CDDA)) || DriveStatus == DS_PLAYING)
1097    {
1098     if(AudioBuffer.ReadPos < AudioBuffer.Size)
1099     {
1100      PSX_WARNING("[CDC] BUG CDDA buffer full");
1101     }
1102     else
1103     {
1104      EnbufferizeCDDASector(buf);
1105     }
1106    }
1107   }
1108  }
1109 
1110  memcpy(SectorPipe[SectorPipe_Pos], read_buf, 2352);
1111  SectorPipe_Pos = (SectorPipe_Pos + 1) % SectorPipe_Count;
1112  SectorPipe_In++;
1113 
1114  PSRCounter += 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
1115 
1116  if(DriveStatus == DS_PLAYING)
1117  {
1118   // FIXME: What's the real fast-forward and backward speed?
1119   if(Forward)
1120    CurSector += 12;
1121   else if(Backward)
1122   {
1123    CurSector -= 12;
1124 
1125    if(CurSector < 0)	// FIXME: How does a real PS handle this condition?
1126     CurSector = 0;
1127   }
1128   else
1129    CurSector++;
1130  }
1131  else
1132   CurSector++;
1133 
1134  if(DriveStatus == DS_PAUSED || DriveStatus == DS_STANDBY) // || DriveStatus == DS_SEEKING_LOGICAL2)
1135  {
1136   if(CurSector >= (SeekTarget + 2))
1137    CurSector = std::max<int32>(-150, CurSector - 9);
1138  }
1139  else
1140   SectorsRead++;
1141 }
1142 
Update(const pscpu_timestamp_t timestamp)1143 pscpu_timestamp_t PS_CDC::Update(const pscpu_timestamp_t timestamp)
1144 {
1145  int32 clocks = timestamp - lastts;
1146 
1147  if(!Cur_CDIF)
1148  {
1149   if(DriveStatus != DS_STOPPED || (PendingCommandCounter > 0 && PendingCommandPhase >= 2))
1150   {
1151    SetAIP(CDCIRQ_DISC_ERROR, (MakeStatus() & ~0xE0) | 0x04, 0x08);
1152 
1153    SectorPipe_Pos = SectorPipe_In = 0;
1154    SectorsRead = 0;
1155    HeaderBufValid = false;
1156    SeekFinished = -1;
1157 
1158    DriveStatus = DS_STOPPED;
1159    PSRCounter = 0;
1160 
1161    if(PendingCommandPhase >= 2)
1162    {
1163     PendingCommand = 0x00;
1164     PendingCommandCounter = 0;
1165     PendingCommandPhase = 0;
1166    }
1167   }
1168 
1169   DiscStartupDelay = 0;
1170  }
1171  //
1172  //
1173  //
1174  while(clocks > 0)
1175  {
1176   int32 chunk_clocks = clocks;
1177 
1178   if(PSRCounter > 0 && chunk_clocks > PSRCounter)
1179    chunk_clocks = PSRCounter;
1180 
1181   if(PendingCommandCounter > 0 && chunk_clocks > PendingCommandCounter)
1182    chunk_clocks = PendingCommandCounter;
1183 
1184   if(chunk_clocks > SPUCounter)
1185    chunk_clocks = SPUCounter;
1186 
1187   if(DiscStartupDelay > 0)
1188   {
1189    if(chunk_clocks > DiscStartupDelay)
1190     chunk_clocks = DiscStartupDelay;
1191 
1192    DiscStartupDelay -= chunk_clocks;
1193 
1194    if(DiscStartupDelay <= 0)
1195    {
1196     SeekTarget = CurSector;
1197     HoldLogicalPos = false;
1198     DriveStatus = DS_PAUSED;	// or is it supposed to be DS_STANDBY?
1199    }
1200   }
1201 
1202   //MDFN_DispMessage("%02x %d -- %d %d -- %02x", IRQBuffer, CDCReadyReceiveCounter, PSRCounter, PendingCommandCounter, PendingCommand);
1203 
1204   if(!(IRQBuffer & 0xF))
1205   {
1206    if(CDCReadyReceiveCounter > 0 && chunk_clocks > CDCReadyReceiveCounter)
1207     chunk_clocks = CDCReadyReceiveCounter;
1208 
1209    if(CDCReadyReceiveCounter > 0)
1210     CDCReadyReceiveCounter -= chunk_clocks;
1211   }
1212 
1213   CheckAIP();
1214 
1215   if(PSRCounter > 0)
1216   {
1217    PSRCounter -= chunk_clocks;
1218 
1219    if(ReportStartupDelay > 0)
1220     ReportStartupDelay -= chunk_clocks;
1221 
1222    if(PSRCounter <= 0)
1223    {
1224     if(DriveStatus == DS_SEEKING)
1225     {
1226      CurSector = SeekTarget;
1227 
1228      HoldLogicalPos = false;
1229      DriveStatus = StatusAfterSeek;
1230      SeekFinished = true;
1231      ReportStartupDelay = 24000000;
1232 
1233      PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
1234     }
1235     else if(DriveStatus == DS_SEEKING_LOGICAL)
1236     {
1237      CurSector = SeekTarget;
1238 
1239      HoldLogicalPos = true;
1240      DriveStatus = DS_SEEKING_LOGICAL2;
1241     }
1242     //
1243     //
1244     //
1245     if(DriveStatus == DS_PAUSED || DriveStatus == DS_STANDBY || DriveStatus == DS_READING || DriveStatus == DS_PLAYING || DriveStatus == DS_SEEKING_LOGICAL2)
1246     {
1247      HandlePlayRead();
1248     }
1249    }
1250   }
1251 
1252   if(PendingCommandCounter > 0)
1253   {
1254    PendingCommandCounter -= chunk_clocks;
1255 
1256    if(PendingCommandCounter <= 0 && CDCReadyReceiveCounter > 0)
1257    {
1258     PendingCommandCounter = CDCReadyReceiveCounter; //256;
1259    }
1260    //else if(PendingCommandCounter <= 0 && PSRCounter > 0 && PSRCounter < 2000)
1261    //{
1262    // PendingCommandCounter = PSRCounter + 1;
1263    //}
1264    else if(PendingCommandCounter <= 0)
1265    {
1266     int32 next_time = 0;
1267 
1268     if(PendingCommandPhase == -1)
1269     {
1270      if(ArgsRP != ArgsWP)
1271      {
1272       ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F];
1273       ArgsRP = (ArgsRP + 1) & 0x1F;
1274       PendingCommandPhase += 1;
1275       next_time = 1815;
1276      }
1277      else
1278      {
1279       PendingCommandPhase += 2;
1280       next_time = 8500;
1281      }
1282     }
1283     else if(PendingCommandPhase == 0)	// Command phase 0
1284     {
1285      if(ArgsReceiveIn < 32)
1286       ArgsReceiveBuf[ArgsReceiveIn++] = ArgsReceiveLatch;
1287 
1288      if(ArgsRP != ArgsWP)
1289      {
1290       ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F];
1291       ArgsRP = (ArgsRP + 1) & 0x1F;
1292       next_time = 1815;
1293      }
1294      else
1295      {
1296       PendingCommandPhase++;
1297       next_time = 8500;
1298      }
1299     }
1300     else if(PendingCommandPhase >= 2)	// Command phase 2+
1301     {
1302      BeginResults();
1303 
1304      const CDC_CTEntry *command = &Commands[PendingCommand];
1305 
1306      next_time = (this->*(command->func2))();
1307     }
1308     else	// Command phase 1
1309     {
1310      if(PendingCommand >= 0x20 || !Commands[PendingCommand].func)
1311      {
1312       BeginResults();
1313 
1314       PSX_WARNING("[CDC] Unknown command: 0x%02x", PendingCommand);
1315 
1316       WriteResult(MakeStatus(true));
1317       WriteResult(ERRCODE_BAD_COMMAND);
1318       WriteIRQ(CDCIRQ_DISC_ERROR);
1319      }
1320      else if(ArgsReceiveIn < Commands[PendingCommand].args_min || ArgsReceiveIn > Commands[PendingCommand].args_max)
1321      {
1322       BeginResults();
1323 
1324       PSX_DBG(PSX_DBG_WARNING, "[CDC] Bad number(%d) of args(first check) for command 0x%02x", ArgsReceiveIn, PendingCommand);
1325       for(unsigned int i = 0; i < ArgsReceiveIn; i++)
1326        PSX_DBG(PSX_DBG_WARNING, " 0x%02x", ArgsReceiveBuf[i]);
1327       PSX_DBG(PSX_DBG_WARNING, "\n");
1328 
1329       WriteResult(MakeStatus(true));
1330       WriteResult(ERRCODE_BAD_NUMARGS);
1331       WriteIRQ(CDCIRQ_DISC_ERROR);
1332      }
1333      else
1334      {
1335       BeginResults();
1336 
1337       const CDC_CTEntry *command = &Commands[PendingCommand];
1338 
1339       PSX_DBG(PSX_DBG_SPARSE, "[CDC] Command: %s --- ", command->name);
1340       for(unsigned int i = 0; i < ArgsReceiveIn; i++)
1341        PSX_DBG(PSX_DBG_SPARSE, " 0x%02x", ArgsReceiveBuf[i]);
1342       PSX_DBG(PSX_DBG_SPARSE, "\n");
1343 
1344       next_time = (this->*(command->func))(ArgsReceiveIn, ArgsReceiveBuf);
1345       PendingCommandPhase = 2;
1346      }
1347      ArgsReceiveIn = 0;
1348     } // end command phase 1
1349 
1350     if(!next_time)
1351      PendingCommandCounter = 0;
1352     else
1353      PendingCommandCounter += next_time;
1354    }
1355   }
1356 
1357   SPUCounter = SPU->UpdateFromCDC(chunk_clocks);
1358 
1359   clocks -= chunk_clocks;
1360  } // end while(clocks > 0)
1361 
1362  lastts = timestamp;
1363 
1364  return(timestamp + CalcNextEvent());
1365 }
1366 
Write(const pscpu_timestamp_t timestamp,uint32 A,uint8 V)1367 void PS_CDC::Write(const pscpu_timestamp_t timestamp, uint32 A, uint8 V)
1368 {
1369  A &= 0x3;
1370 
1371  //printf("Write: %08x %02x\n", A, V);
1372 
1373  if(A == 0x00)
1374  {
1375   RegSelector = V & 0x3;
1376  }
1377  else
1378  {
1379   const unsigned reg_index = ((RegSelector & 0x3) * 3) + (A - 1);
1380 
1381   Update(timestamp);
1382   //PSX_WARNING("[CDC] Write to register 0x%02x: 0x%02x @ %d --- 0x%02x 0x%02x\n", reg_index, V, timestamp, DMABuffer.CanRead(), IRQBuffer);
1383 
1384   switch(reg_index)
1385   {
1386 	default:
1387 		PSX_WARNING("[CDC] Unknown write to register 0x%02x: 0x%02x\n", reg_index, V);
1388 		break;
1389 
1390 	 case 0x00:
1391 		if(PendingCommandCounter > 0)
1392 		{
1393 		 PSX_WARNING("[CDC] WARNING: Interrupting command 0x%02x, phase=%d, timeleft=%d with command=0x%02x", PendingCommand, PendingCommandPhase,
1394 			PendingCommandCounter, V);
1395 		}
1396 
1397 		if(IRQBuffer & 0xF)
1398 		{
1399 		 PSX_WARNING("[CDC] Attempting to start command(0x%02x) while IRQBuffer(0x%02x) is not clear.", V, IRQBuffer);
1400 		}
1401 
1402 		if(ResultsIn > 0)
1403 		{
1404 		 PSX_WARNING("[CDC] Attempting to start command(0x%02x) while command results(count=%d) still in buffer.", V, ResultsIn);
1405 		}
1406 
1407          	PendingCommandCounter = 10500 + PSX_GetRandU32(0, 3000) + 1815;
1408 	 	PendingCommand = V;
1409          	PendingCommandPhase = -1;
1410 		ArgsReceiveIn = 0;
1411 		break;
1412 
1413 	 case 0x01:
1414 		ArgsBuf[ArgsWP & 0xF] = V;
1415 		ArgsWP = (ArgsWP + 1) & 0x1F;
1416 
1417 		if(!((ArgsWP - ArgsRP) & 0x0F))
1418 		{
1419 		 PSX_WARNING("[CDC] Argument buffer overflow");
1420 		}
1421 		break;
1422 
1423 	 case 0x02:
1424  	 	if(V & 0x80)
1425 	 	{
1426 	  	 if(!DMABuffer.CanRead())
1427 	  	 {
1428 		  if(!SB_In)
1429 		  {
1430 		   PSX_WARNING("[CDC] Data read begin when no data to read!");
1431 
1432 		   DMABuffer.Write(SB, 2340);
1433 
1434 		   while(DMABuffer.CanWrite())
1435 		    DMABuffer.WriteByte(0x00);
1436 		  }
1437 		  else
1438 		  {
1439 	   	   DMABuffer.Write(SB, SB_In);
1440 		   SB_In = 0;
1441 		  }
1442 	  	 }
1443 		 else
1444 		 {
1445 		  //PSX_WARNING("[CDC] Attempt to start data transfer via 0x80->1803 when %d bytes still in buffer", DMABuffer.CanRead());
1446 		 }
1447 	 	}
1448 	 	else if(V & 0x40)	// Something CD-DA related(along with & 0x20 ???)?
1449 	 	{
1450 		 for(unsigned i = 0; i < 4 && DMABuffer.CanRead(); i++)
1451 		  DMABuffer.ReadByte();
1452 		}
1453 		else
1454 		{
1455 		 DMABuffer.Flush();
1456 		}
1457 
1458 		if(V & 0x20)
1459 		{
1460 		 PSX_WARNING("[CDC] Mystery IRQ trigger bit set.");
1461 		 IRQBuffer |= 0x10;
1462 		 RecalcIRQ();
1463 		}
1464 		break;
1465 
1466 	 case 0x04:
1467 	 	IRQOutTestMask = V;
1468 		RecalcIRQ();
1469 		break;
1470 
1471 	 case 0x05:
1472 		if((IRQBuffer &~ V) != IRQBuffer && ResultsIn)
1473 		{
1474 		 // To debug icky race-condition related problems in "Psychic Detective", and to see if any games suffer from the same potential issue
1475 		 // (to know what to test when we emulate CPU more accurately in regards to pipeline stalls and timing, which could throw off our kludge
1476 		 //  for this issue)
1477 		 PSX_WARNING("[CDC] Acknowledged IRQ(wrote 0x%02x, before_IRQBuffer=0x%02x) while %u bytes in results buffer.", V, IRQBuffer, ResultsIn);
1478 		}
1479 
1480 	 	IRQBuffer &= ~V;
1481 	 	RecalcIRQ();
1482 
1483 		if(V & 0x80)	// Forced CD hardware reset of some kind(interface, controller, and drive?)  Seems to take a while(relatively speaking) to complete.
1484 		{
1485 		 PSX_WARNING("[CDC] Soft Reset");
1486 		 SoftReset();
1487 		}
1488 
1489 		if(V & 0x40)	// Does it clear more than arguments buffer?  Doesn't appear to clear results buffer.
1490 		{
1491 		 ArgsWP = ArgsRP = 0;
1492 		}
1493 		break;
1494 
1495 	 case 0x07:
1496 		Pending_DecodeVolume[0][0] = V;
1497 		break;
1498 
1499 	 case 0x08:
1500 		Pending_DecodeVolume[0][1] = V;
1501 		break;
1502 
1503 	 case 0x09:
1504 		Pending_DecodeVolume[1][1] = V;
1505 		break;
1506 
1507 	 case 0x0A:
1508 		Pending_DecodeVolume[1][0] = V;
1509 		break;
1510 
1511 	 case 0x0B:
1512 		if(V & 0x20)
1513 		{
1514 		 memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));
1515 
1516 		 for(int i = 0; i < 2; i++)
1517 		 {
1518 		  for(int o = 0; o < 2; o++)
1519 		  {
1520 		   //fprintf(stderr, "Input Channel %d, Output Channel %d -- Volume=%d\n", i, o, DecodeVolume[i][o]);
1521 		  }
1522 		 }
1523 		}
1524 		break;
1525   }
1526   PSX_SetEventNT(PSX_EVENT_CDC, timestamp + CalcNextEvent());
1527  }
1528 }
1529 
Read(const pscpu_timestamp_t timestamp,uint32 A)1530 uint8 PS_CDC::Read(const pscpu_timestamp_t timestamp, uint32 A)
1531 {
1532  uint8 ret = 0;
1533 
1534  A &= 0x03;
1535 
1536  //printf("Read %08x\n", A);
1537 
1538  if(A == 0x00)
1539  {
1540 	ret = RegSelector & 0x3;
1541 
1542 	if(ArgsWP == ArgsRP)
1543 	 ret |= 0x08;	// Args FIFO empty.
1544 
1545 	if(!((ArgsWP - ArgsRP) & 0x10))
1546 	 ret |= 0x10;	// Args FIFO has room.
1547 
1548 	if(ResultsIn)
1549 	 ret |= 0x20;
1550 
1551 	if(DMABuffer.CanRead())
1552 	 ret |= 0x40;
1553 
1554         if(PendingCommandCounter > 0 && PendingCommandPhase <= 1)
1555 	 ret |= 0x80;
1556  }
1557  else
1558  {
1559   switch(A & 0x3)
1560   {
1561    case 0x01:
1562 	ret = ReadResult();
1563 	break;
1564 
1565    case 0x02:
1566 	//PSX_WARNING("[CDC] DMA Buffer manual read");
1567 	if(DMABuffer.CanRead())
1568 	 ret = DMABuffer.ReadByte();
1569 	else
1570 	{
1571 	 PSX_WARNING("[CDC] CD data transfer port read, but no data present!");
1572 	}
1573 	break;
1574 
1575    case 0x03:
1576 	if(RegSelector & 0x1)
1577 	{
1578 	 ret = 0xE0 | IRQBuffer;
1579 	}
1580 	else
1581 	{
1582 	 ret = 0xFF;
1583 	}
1584 	break;
1585   }
1586  }
1587 
1588  return(ret);
1589 }
1590 
1591 
DMACanRead(void)1592 bool PS_CDC::DMACanRead(void)
1593 {
1594  return(DMABuffer.CanRead());
1595 }
1596 
DMARead(void)1597 uint32 PS_CDC::DMARead(void)
1598 {
1599  uint32 data = 0;
1600 
1601  for(int i = 0; i < 4; i++)
1602  {
1603   if(DMABuffer.CanRead())
1604    data |= DMABuffer.ReadByte() << (i * 8);
1605   else
1606   {
1607    PSX_WARNING("[CDC] DMA read buffer underflow!");
1608   }
1609  }
1610 
1611  return(data);
1612 }
1613 
CommandCheckDiscPresent(void)1614 bool PS_CDC::CommandCheckDiscPresent(void)
1615 {
1616  if(!Cur_CDIF || DiscStartupDelay > 0)
1617  {
1618   WriteResult(MakeStatus(true));
1619   WriteResult(ERRCODE_NOT_READY);
1620 
1621   WriteIRQ(CDCIRQ_DISC_ERROR);
1622 
1623   return(false);
1624  }
1625 
1626  return(true);
1627 }
1628 
Command_Nop(const int arg_count,const uint8 * args)1629 int32 PS_CDC::Command_Nop(const int arg_count, const uint8 *args)
1630 {
1631  WriteResult(MakeStatus());
1632  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1633 
1634  return(0);
1635 }
1636 
Command_Setloc(const int arg_count,const uint8 * args)1637 int32 PS_CDC::Command_Setloc(const int arg_count, const uint8 *args)
1638 {
1639  uint8 m, s, f;
1640 
1641  if((args[0] & 0x0F) > 0x09 || args[0] > 0x99 ||
1642     (args[1] & 0x0F) > 0x09 || args[1] > 0x59 ||
1643     (args[2] & 0x0F) > 0x09 || args[2] > 0x74)
1644  {
1645   WriteResult(MakeStatus(true));
1646   WriteResult(ERRCODE_BAD_ARGVAL);
1647   WriteIRQ(CDCIRQ_DISC_ERROR);
1648   return(0);
1649  }
1650 
1651  m = BCD_to_U8(args[0]);
1652  s = BCD_to_U8(args[1]);
1653  f = BCD_to_U8(args[2]);
1654 
1655  CommandLoc = f + 75 * s + 75 * 60 * m - 150;
1656  CommandLoc_Dirty = true;
1657 
1658  WriteResult(MakeStatus());
1659  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1660 
1661  return(0);
1662 }
1663 
CalcSeekTime(int32 initial,int32 target,bool motor_on,bool paused)1664 int32 PS_CDC::CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused)
1665 {
1666  int32 ret = 0;
1667 
1668  if(!motor_on)
1669  {
1670   initial = 0;
1671   ret += 33868800;
1672  }
1673 
1674  const int32 abs_diff = abs(initial - target);
1675 
1676  ret += std::max<int64>((int64)abs_diff * 33868800 * 1000 / (72 * 60 * 75) / 1000, 20000);
1677 
1678  if(abs_diff >= 2250)
1679   ret += (int64)33868800 * 300 / 1000;
1680  else if(paused)
1681  {
1682   // The delay to restart from a Pause state is...very....WEIRD.  The time it takes is related to the amount of time that has passed since the pause, and
1683   // where on the disc the laser head is, with generally more time passed = longer to resume, except that there's a window of time where it takes a
1684   // ridiculous amount of time when not much time has passed.
1685   //
1686   // What we have here will be EXTREMELY simplified.
1687 
1688   //
1689   //
1690 
1691   //if(time_passed >= 67737)
1692   //{
1693   //}
1694   //else
1695   {
1696    // Take twice as long for 1x mode.
1697    ret += 1237952 * ((Mode & MODE_SPEED) ? 1 : 2);
1698   }
1699  }
1700  else if(abs_diff >= 3 && abs_diff < 12)
1701   ret += 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1)) * 4;
1702 
1703  //else if(target < initial)
1704  // ret += 1000000;
1705 
1706  ret += PSX_GetRandU32(0, 25000);
1707 
1708  PSX_DBG(PSX_DBG_SPARSE, "[CDC] CalcSeekTime() %d->%d = %d\n", initial, target, ret);
1709 
1710  return(ret);
1711 }
1712 
1713 #if 0
1714 void PS_CDC::BeginSeek(uint32 target, int after_seek)
1715 {
1716  SeekTarget = target;
1717  StatusAfterSeek = after_seek;
1718 
1719  PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
1720 }
1721 #endif
1722 
1723 // Remove this function when we have better seek emulation; it's here because the Rockman complete works games(at least 2 and 4) apparently have finicky fubared CD
1724 // access code.
PreSeekHack(int32 target)1725 void PS_CDC::PreSeekHack(int32 target)
1726 {
1727  uint8 pwbuf[96];
1728  int max_try = 32;
1729 
1730  CurSector = target;	// If removing/changing this, take into account how it will affect ReadN/ReadS/Play/etc command calls that interrupt a seek.
1731  SeekRetryCounter = 128;
1732 
1733  // If removing this SubQ reading bit, think about how it will interact with a Read command of data(or audio :b) sectors when Mode bit0 is 1.
1734  do
1735  {
1736   Cur_CDIF->ReadRawSectorPWOnly(pwbuf, target++, true);
1737  } while(!DecodeSubQ(pwbuf) && --max_try > 0);
1738 }
1739 
1740 /*
1741  Play command with a track argument that's not a valid BCD quantity causes interesting half-buggy behavior on an actual PS1(unlike some of the other commands,
1742  an error doesn't seem to be generated for a bad BCD argument).
1743 */
Command_Play(const int arg_count,const uint8 * args)1744 int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
1745 {
1746  if(!CommandCheckDiscPresent())
1747   return(0);
1748 
1749  ClearAIP();
1750 
1751  WriteResult(MakeStatus());
1752  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1753 
1754  Forward = Backward = false;
1755 
1756  if(arg_count && args[0])
1757  {
1758   int track = BCD_to_U8(args[0]);
1759 
1760   if(track < toc.first_track)
1761   {
1762    PSX_WARNING("[CDC] Attempt to play track before first track.");
1763    track = toc.first_track;
1764   }
1765   else if(track > toc.last_track)
1766   {
1767    PSX_WARNING("[CDC] Attempt to play track after last track.");
1768    track = toc.last_track;
1769   }
1770 
1771   ClearAudioBuffers();
1772   SectorPipe_Pos = SectorPipe_In = 0;
1773   SectorsRead = 0;
1774 
1775   PlayTrackMatch = track;
1776 
1777   PSX_WARNING("[CDC] Play track: %d", track);
1778 
1779   SeekTarget = toc.tracks[track].lba;
1780   PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
1781   HeaderBufValid = false;
1782   PreSeekHack(SeekTarget);
1783 
1784   SeekFinished = false;
1785   DriveStatus = DS_SEEKING;
1786   StatusAfterSeek = DS_PLAYING;
1787  }
1788  else if(CommandLoc_Dirty || DriveStatus != DS_PLAYING)
1789  {
1790   ClearAudioBuffers();
1791   SectorPipe_Pos = SectorPipe_In = 0;
1792   SectorsRead = 0;
1793 
1794   if(CommandLoc_Dirty)
1795    SeekTarget = CommandLoc;
1796   else
1797    SeekTarget = CurSector;
1798 
1799   PlayTrackMatch = -1;
1800 
1801   PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
1802   HeaderBufValid = false;
1803   PreSeekHack(SeekTarget);
1804 
1805   SeekFinished = false;
1806   DriveStatus = DS_SEEKING;
1807   StatusAfterSeek = DS_PLAYING;
1808  }
1809 
1810  CommandLoc_Dirty = false;
1811  return(0);
1812 }
1813 
Command_Forward(const int arg_count,const uint8 * args)1814 int32 PS_CDC::Command_Forward(const int arg_count, const uint8 *args)
1815 {
1816  if(!CommandCheckDiscPresent())
1817   return(0);
1818 
1819  WriteResult(MakeStatus());
1820  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1821 
1822  Backward = false;
1823  Forward = true;
1824 
1825  return(0);
1826 }
1827 
Command_Backward(const int arg_count,const uint8 * args)1828 int32 PS_CDC::Command_Backward(const int arg_count, const uint8 *args)
1829 {
1830  if(!CommandCheckDiscPresent())
1831   return(0);
1832 
1833  WriteResult(MakeStatus());
1834  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1835 
1836  Backward = true;
1837  Forward = false;
1838 
1839  return(0);
1840 }
1841 
1842 
ReadBase(void)1843 void PS_CDC::ReadBase(void)
1844 {
1845  if(!CommandCheckDiscPresent())
1846   return;
1847 
1848  if(!IsPSXDisc)
1849  {
1850   WriteResult(MakeStatus(true));
1851   WriteResult(ERRCODE_BAD_COMMAND);
1852 
1853   WriteIRQ(CDCIRQ_DISC_ERROR);
1854   return;
1855  }
1856 
1857  WriteResult(MakeStatus());
1858  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1859 
1860  if((DriveStatus == DS_SEEKING_LOGICAL || DriveStatus == DS_SEEKING_LOGICAL2) && SeekTarget == CommandLoc && StatusAfterSeek == DS_READING)
1861  {
1862   CommandLoc_Dirty = false;
1863   return;
1864  }
1865 
1866  if(CommandLoc_Dirty || DriveStatus != DS_READING)
1867  {
1868   // Don't flush the DMABuffer here; see CTR course selection screen.
1869   ClearAIP();
1870   ClearAudioBuffers();
1871   SB_In = 0;
1872   SectorPipe_Pos = SectorPipe_In = 0;
1873   SectorsRead = 0;
1874 
1875   // TODO: separate motor start from seek phase?
1876 
1877   if(CommandLoc_Dirty)
1878    SeekTarget = CommandLoc;
1879   else if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
1880    SeekTarget = CurSector;
1881 
1882   PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1)) + CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
1883   HeaderBufValid = false;
1884   PreSeekHack(SeekTarget);
1885 
1886   SeekFinished = false;
1887   DriveStatus = DS_SEEKING_LOGICAL;
1888   StatusAfterSeek = DS_READING;
1889  }
1890 
1891  CommandLoc_Dirty = false;
1892 }
1893 
Command_ReadN(const int arg_count,const uint8 * args)1894 int32 PS_CDC::Command_ReadN(const int arg_count, const uint8 *args)
1895 {
1896  ReadBase();
1897  return 0;
1898 }
1899 
Command_ReadS(const int arg_count,const uint8 * args)1900 int32 PS_CDC::Command_ReadS(const int arg_count, const uint8 *args)
1901 {
1902  ReadBase();
1903  return 0;
1904 }
1905 
Command_Stop(const int arg_count,const uint8 * args)1906 int32 PS_CDC::Command_Stop(const int arg_count, const uint8 *args)
1907 {
1908  if(!CommandCheckDiscPresent())
1909   return(0);
1910 
1911  WriteResult(MakeStatus());
1912  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1913 
1914  if(DriveStatus == DS_STOPPED)
1915  {
1916   return(5000);
1917  }
1918  else
1919  {
1920   ClearAudioBuffers();
1921   ClearAIP();
1922   SectorPipe_Pos = SectorPipe_In = 0;
1923   SectorsRead = 0;
1924 
1925   DriveStatus = DS_STOPPED;
1926   HeaderBufValid = false;
1927 
1928   return(33868);	// FIXME, should be much higher.
1929  }
1930 }
1931 
Command_Stop_Part2(void)1932 int32 PS_CDC::Command_Stop_Part2(void)
1933 {
1934  PSRCounter = 0;
1935 
1936  WriteResult(MakeStatus());
1937  WriteIRQ(CDCIRQ_COMPLETE);
1938 
1939  return(0);
1940 }
1941 
Command_Standby(const int arg_count,const uint8 * args)1942 int32 PS_CDC::Command_Standby(const int arg_count, const uint8 *args)
1943 {
1944  if(!CommandCheckDiscPresent())
1945   return(0);
1946 
1947  if(DriveStatus != DS_STOPPED)
1948  {
1949   WriteResult(MakeStatus(true));
1950   WriteResult(0x20);
1951   WriteIRQ(CDCIRQ_DISC_ERROR);
1952   return(0);
1953  }
1954 
1955  WriteResult(MakeStatus());
1956  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1957 
1958  ClearAudioBuffers();
1959  ClearAIP();
1960  SectorPipe_Pos = SectorPipe_In = 0;
1961  SectorsRead = 0;
1962 
1963  SeekTarget = CurSector;	// FIXME?  CurSector = 0?
1964  HoldLogicalPos = false;
1965  DriveStatus = DS_STANDBY;
1966 
1967  return((int64)33868800 * 100 / 1000);	// No idea, FIXME.
1968 }
1969 
Command_Standby_Part2(void)1970 int32 PS_CDC::Command_Standby_Part2(void)
1971 {
1972  PSRCounter = 0;
1973 
1974  WriteResult(MakeStatus());
1975  WriteIRQ(CDCIRQ_COMPLETE);
1976 
1977  return(0);
1978 }
1979 
Command_Pause(const int arg_count,const uint8 * args)1980 int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args)
1981 {
1982  if(!CommandCheckDiscPresent())
1983   return 0;
1984 
1985  WriteResult(MakeStatus());
1986  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1987 
1988  if(DriveStatus == DS_PAUSED || DriveStatus == DS_STOPPED)
1989  {
1990   return 5000;
1991  }
1992  else
1993  {
1994   CurSector -= std::min<uint32>(4, SectorsRead);	// See: Bedlam, Rise 2
1995   SectorsRead = 0;
1996 
1997   // "Viewpoint" flips out and crashes if reading isn't stopped (almost?) immediately.
1998   //ClearAudioBuffers();
1999   SectorPipe_Pos = SectorPipe_In = 0;
2000   ClearAIP();
2001   SeekTarget = CurSector;
2002   DriveStatus = DS_PAUSED;
2003   PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
2004 
2005   // An approximation.
2006   return (1124584 + ((int64)CurSector * 42596 / (75 * 60))) * ((Mode & MODE_SPEED) ? 1 : 2) + PSX_GetRandU32(0, 100000);
2007  }
2008 }
2009 
Command_Pause_Part2(void)2010 int32 PS_CDC::Command_Pause_Part2(void)
2011 {
2012  WriteResult(MakeStatus());
2013  WriteIRQ(CDCIRQ_COMPLETE);
2014 
2015  return 0;
2016 }
2017 
Command_Reset(const int arg_count,const uint8 * args)2018 int32 PS_CDC::Command_Reset(const int arg_count, const uint8 *args)
2019 {
2020  WriteResult(MakeStatus());
2021  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2022 
2023  Muted = false; // Does it get reset here?
2024  Mode = 0x20;	// Confirmed(and see "This Is Football 2").
2025  CommandLoc = 0;
2026  //
2027  //
2028  //
2029 // printf("DriveStatus: %d %d %d\n", DriveStatus, StatusAfterSeek, SeekTarget);
2030  if(Cur_CDIF && DiscStartupDelay <= 0)
2031  {
2032   if((DriveStatus == DS_SEEKING_LOGICAL || DriveStatus == DS_SEEKING) && StatusAfterSeek == DS_PAUSED && SeekTarget == 0)
2033   {
2034    //puts("HRMPH");
2035    return 256;
2036   }
2037   else
2038   {
2039    ClearAudioBuffers();
2040 
2041    SB_In = 0;
2042    SectorPipe_Pos = SectorPipe_In = 0;
2043    SectorsRead = 0;
2044 
2045    SeekTarget = 0;
2046    PSRCounter = std::max<int32>(PSX_GetRandU32(0, 3250000), CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED));
2047    PreSeekHack(SeekTarget);
2048    SeekFinished = false;
2049    DriveStatus = HoldLogicalPos ? DS_SEEKING_LOGICAL : DS_SEEKING;
2050    StatusAfterSeek = DS_PAUSED;
2051    ClearAIP();
2052 
2053    return 4100000;
2054   }
2055  }
2056  else
2057  {
2058   SeekFinished = true;
2059   return 70000;
2060  }
2061 }
2062 
Command_Mute(const int arg_count,const uint8 * args)2063 int32 PS_CDC::Command_Mute(const int arg_count, const uint8 *args)
2064 {
2065  Muted = true;
2066 
2067  WriteResult(MakeStatus());
2068  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2069 
2070  return(0);
2071 }
2072 
Command_Demute(const int arg_count,const uint8 * args)2073 int32 PS_CDC::Command_Demute(const int arg_count, const uint8 *args)
2074 {
2075  Muted = false;
2076 
2077  WriteResult(MakeStatus());
2078  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2079 
2080  return(0);
2081 }
2082 
Command_Setfilter(const int arg_count,const uint8 * args)2083 int32 PS_CDC::Command_Setfilter(const int arg_count, const uint8 *args)
2084 {
2085  FilterFile = args[0];
2086  FilterChan = args[1];
2087 
2088  //PSX_WARNING("[CDC] Setfilter: %02x %02x", args[0], args[1]);
2089 
2090  WriteResult(MakeStatus());
2091  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2092 
2093  return(0);
2094 }
2095 
Command_Setmode(const int arg_count,const uint8 * args)2096 int32 PS_CDC::Command_Setmode(const int arg_count, const uint8 *args)
2097 {
2098  Mode = args[0];
2099 
2100  WriteResult(MakeStatus());
2101  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2102 
2103  return(0);
2104 }
2105 
Command_Getparam(const int arg_count,const uint8 * args)2106 int32 PS_CDC::Command_Getparam(const int arg_count, const uint8 *args)
2107 {
2108  WriteResult(MakeStatus());
2109  WriteResult(Mode);
2110  WriteResult(0x00);
2111  WriteResult(FilterFile);
2112  WriteResult(FilterChan);
2113 
2114  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2115 
2116 
2117  return(0);
2118 }
2119 
Command_GetlocL(const int arg_count,const uint8 * args)2120 int32 PS_CDC::Command_GetlocL(const int arg_count, const uint8 *args)
2121 {
2122  if(!CommandCheckDiscPresent())
2123   return(0);
2124 
2125  if(!HeaderBufValid)
2126  {
2127   WriteResult(MakeStatus(true));
2128   WriteResult(0x80);
2129   WriteIRQ(CDCIRQ_DISC_ERROR);
2130   return(0);
2131  }
2132 
2133  for(unsigned i = 0; i < 8; i++)
2134  {
2135   //printf("%d %d: %02x\n", DriveStatus, i, HeaderBuf[i]);
2136   WriteResult(HeaderBuf[i]);
2137  }
2138 
2139  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2140 
2141  return(0);
2142 }
2143 
Command_GetlocP(const int arg_count,const uint8 * args)2144 int32 PS_CDC::Command_GetlocP(const int arg_count, const uint8 *args)
2145 {
2146  if(!CommandCheckDiscPresent())
2147   return(0);
2148 
2149  //printf("%2x:%2x %2x:%2x:%2x %2x:%2x:%2x\n", SubQBuf_Safe[0x1], SubQBuf_Safe[0x2], SubQBuf_Safe[0x3], SubQBuf_Safe[0x4], SubQBuf_Safe[0x5], SubQBuf_Safe[0x7], SubQBuf_Safe[0x8], SubQBuf_Safe[0x9]);
2150 
2151  WriteResult(SubQBuf_Safe[0x1]);	// Track
2152  WriteResult(SubQBuf_Safe[0x2]);	// Index
2153  WriteResult(SubQBuf_Safe[0x3]);	// R M
2154  WriteResult(SubQBuf_Safe[0x4]);	// R S
2155  WriteResult(SubQBuf_Safe[0x5]);	// R F
2156  WriteResult(SubQBuf_Safe[0x7]);	// A M
2157  WriteResult(SubQBuf_Safe[0x8]);	// A S
2158  WriteResult(SubQBuf_Safe[0x9]);	// A F
2159 
2160  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2161 
2162  return(0);
2163 }
2164 
Command_ReadT(const int arg_count,const uint8 * args)2165 int32 PS_CDC::Command_ReadT(const int arg_count, const uint8 *args)
2166 {
2167  WriteResult(MakeStatus());
2168  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2169 
2170  return(44100 * 768 / 1000);
2171 }
2172 
Command_ReadT_Part2(void)2173 int32 PS_CDC::Command_ReadT_Part2(void)
2174 {
2175  WriteResult(MakeStatus());
2176  WriteIRQ(CDCIRQ_COMPLETE);
2177 
2178  return(0);
2179 }
2180 
Command_GetTN(const int arg_count,const uint8 * args)2181 int32 PS_CDC::Command_GetTN(const int arg_count, const uint8 *args)
2182 {
2183  if(!CommandCheckDiscPresent())
2184   return(0);
2185 
2186  WriteResult(MakeStatus());
2187  WriteResult(U8_to_BCD(toc.first_track));
2188  WriteResult(U8_to_BCD(toc.last_track));
2189 
2190  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2191 
2192  return(0);
2193 }
2194 
Command_GetTD(const int arg_count,const uint8 * args)2195 int32 PS_CDC::Command_GetTD(const int arg_count, const uint8 *args)
2196 {
2197  if(!CommandCheckDiscPresent())
2198   return(0);
2199 
2200  int track;
2201  uint8 m, s, f;
2202 
2203  if(!args[0])
2204   track = 100;
2205  else
2206  {
2207   track = BCD_to_U8(args[0]);
2208 
2209   if(!BCD_is_valid(args[0]) || track < toc.first_track || track > toc.last_track)	// Error
2210   {
2211    WriteResult(MakeStatus(true));
2212    WriteResult(ERRCODE_BAD_ARGVAL);
2213    WriteIRQ(CDCIRQ_DISC_ERROR);
2214    return(0);
2215   }
2216  }
2217 
2218  LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
2219 
2220  WriteResult(MakeStatus());
2221  WriteResult(U8_to_BCD(m));
2222  WriteResult(U8_to_BCD(s));
2223  //WriteResult(U8_to_BCD(f));
2224 
2225  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2226 
2227  return(0);
2228 }
2229 
Command_SeekL(const int arg_count,const uint8 * args)2230 int32 PS_CDC::Command_SeekL(const int arg_count, const uint8 *args)
2231 {
2232  if(!CommandCheckDiscPresent())
2233   return(0);
2234 
2235  WriteResult(MakeStatus());
2236  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2237 
2238  SeekTarget = CommandLoc;
2239 
2240 #if 1
2241  SectorsRead = 0;
2242  SectorPipe_Pos = SectorPipe_In = 0;
2243 #endif
2244  PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
2245  //HeaderBufValid = false;
2246  PreSeekHack(SeekTarget);
2247  SeekFinished = false;
2248  DriveStatus = DS_SEEKING_LOGICAL;
2249  StatusAfterSeek = DS_STANDBY;
2250  ClearAIP();
2251 
2252  return(PSRCounter);
2253 }
2254 
Command_SeekP(const int arg_count,const uint8 * args)2255 int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args)
2256 {
2257  if(!CommandCheckDiscPresent())
2258   return(0);
2259 
2260  WriteResult(MakeStatus());
2261  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2262 
2263  SeekTarget = CommandLoc;
2264 
2265  PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
2266  HeaderBufValid = false;
2267  PreSeekHack(SeekTarget);
2268  SeekFinished = false;
2269  DriveStatus = DS_SEEKING;
2270  StatusAfterSeek = DS_STANDBY;
2271  ClearAIP();
2272 
2273  return(PSRCounter);
2274 }
2275 
2276 // Used with Command_Reset(), too.
Command_Seek_PartN(void)2277 int32 PS_CDC::Command_Seek_PartN(void)
2278 {
2279  if(DriveStatus != DS_SEEKING && DriveStatus != DS_SEEKING_LOGICAL && DriveStatus != DS_SEEKING_LOGICAL2)
2280  {
2281   if(SeekFinished)
2282   {
2283    BeginResults();
2284 
2285    if(SeekFinished < 0)
2286    {
2287     WriteResult(MakeStatus() | 0x04);
2288     WriteResult(0x04);
2289     WriteIRQ(CDCIRQ_DISC_ERROR);
2290    }
2291    else
2292    {
2293     WriteResult(MakeStatus());
2294     WriteIRQ(CDCIRQ_COMPLETE);
2295    }
2296   }
2297   else
2298   {
2299    PSX_WARNING("[CDC] DriveStatus no longer seeking, but SeekFinished is still 0.");
2300   }
2301 
2302   return 0;
2303  }
2304  else
2305  {
2306   return std::max<int32>(PSRCounter, 256);
2307  }
2308 }
2309 
Command_Test(const int arg_count,const uint8 * args)2310 int32 PS_CDC::Command_Test(const int arg_count, const uint8 *args)
2311 {
2312  //PSX_WARNING("[CDC] Test command sub-operation: 0x%02x", args[0]);
2313 
2314  switch(args[0])
2315  {
2316   default:
2317 	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2318 	WriteResult(MakeStatus(true));
2319 	WriteResult(0x10);
2320 	WriteIRQ(CDCIRQ_DISC_ERROR);
2321 	break;
2322 
2323   case 0x00:
2324   case 0x01:
2325   case 0x02:
2326   case 0x03:
2327   case 0x10:
2328   case 0x11:
2329   case 0x12:
2330   case 0x13:
2331   case 0x14:
2332   case 0x15:
2333   case 0x16:
2334   case 0x17:
2335   case 0x18:
2336   case 0x19:
2337   case 0x1A:
2338 	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2339 	WriteResult(MakeStatus());
2340 	WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2341   	break;
2342 
2343 #if 0
2344   case 0x50:	// *Need to retest this test command, it takes additional arguments??? Or in any case, it generates a different error code(0x20) than most other Test
2345 		// sub-commands that generate an error code(0x10).
2346 	break;
2347 
2348  // Same with 0x60, 0x71-0x76
2349 
2350 #endif
2351 
2352   case 0x51:	// *Need to retest this test command
2353 	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2354 	WriteResult(0x01);
2355 	WriteResult(0x00);
2356 	WriteResult(0x00);
2357 	break;
2358 
2359   case 0x75:	// *Need to retest this test command
2360 	PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2361 	WriteResult(0x00);
2362 	WriteResult(0xC0);
2363 	WriteResult(0x00);
2364 	WriteResult(0x00);
2365 	break;
2366 
2367   //
2368   // SCEx counters not reset by command 0x0A.
2369   //
2370 
2371   case 0x04:	// Reset SCEx counters
2372 	WriteResult(MakeStatus());
2373 	WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2374   	break;
2375 
2376   case 0x05:	// Read SCEx counters
2377 	WriteResult(0x00);	// Number of TOC/leadin reads? (apparently increases by 1 or 2 per ReadTOC, even on non-PSX music CD)
2378 	WriteResult(0x00);	// Number of SCEx strings received? (Stays at zero on music CD)
2379 	WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2380   	break;
2381 
2382   case 0x20:
2383 	{
2384 	 WriteResult(0x97);
2385 	 WriteResult(0x01);
2386 	 WriteResult(0x10);
2387 	 WriteResult(0xC2);
2388 
2389 	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2390 	}
2391 	break;
2392 
2393   case 0x21:	// *Need to retest this test command.
2394 	{
2395 	 WriteResult(0x01);
2396 	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2397 	}
2398 	break;
2399 
2400   case 0x22:
2401 	{
2402 	 static const uint8 td[7] = { 0x66, 0x6f, 0x72, 0x20, 0x55, 0x2f, 0x43 };
2403 
2404 	 for(unsigned i = 0; i < 7; i++)
2405 	  WriteResult(td[i]);
2406 
2407 	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2408 	}
2409 	break;
2410 
2411   case 0x23:
2412   case 0x24:
2413 	{
2414 	 static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x32, 0x35, 0x34, 0x35, 0x51 };
2415 
2416 	 for(unsigned i = 0; i < 8; i++)
2417 	  WriteResult(td[i]);
2418 
2419 	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2420 	}
2421 	break;
2422 
2423   case 0x25:
2424 	{
2425 	 static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x31, 0x38, 0x31, 0x35, 0x51 };
2426 
2427 	 for(unsigned i = 0; i < 8; i++)
2428 	  WriteResult(td[i]);
2429 
2430 	 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2431 	}
2432 	break;
2433  }
2434  return(0);
2435 }
2436 
Command_ID(const int arg_count,const uint8 * args)2437 int32 PS_CDC::Command_ID(const int arg_count, const uint8 *args)
2438 {
2439  if(!CommandCheckDiscPresent())
2440   return(0);
2441 
2442  WriteResult(MakeStatus());
2443  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2444 
2445  return(33868);
2446 }
2447 
Command_ID_Part2(void)2448 int32 PS_CDC::Command_ID_Part2(void)
2449 {
2450  if(IsPSXDisc)
2451  {
2452   WriteResult(MakeStatus());
2453   WriteResult(0x00);
2454   WriteResult(0x20);
2455   WriteResult(0x00);
2456  }
2457  else
2458  {
2459   WriteResult(MakeStatus() | 0x08);
2460   WriteResult(0x90);
2461   WriteResult(toc.disc_type);
2462   WriteResult(0x00);
2463  }
2464 
2465  if(IsPSXDisc)
2466  {
2467   WriteResult(DiscID[0]);
2468   WriteResult(DiscID[1]);
2469   WriteResult(DiscID[2]);
2470   WriteResult(DiscID[3]);
2471  }
2472  else
2473  {
2474   WriteResult(0xff);
2475   WriteResult(0);
2476   WriteResult(0);
2477   WriteResult(0);
2478  }
2479 
2480  if(IsPSXDisc)
2481   WriteIRQ(CDCIRQ_COMPLETE);
2482  else
2483   WriteIRQ(CDCIRQ_DISC_ERROR);
2484 
2485  return(0);
2486 }
2487 
Command_Init(const int arg_count,const uint8 * args)2488 int32 PS_CDC::Command_Init(const int arg_count, const uint8 *args)
2489 {
2490  return(0);
2491 }
2492 
Command_ReadTOC(const int arg_count,const uint8 * args)2493 int32 PS_CDC::Command_ReadTOC(const int arg_count, const uint8 *args)
2494 {
2495  int32 ret_time;
2496 
2497  HeaderBufValid = false;
2498  WriteResult(MakeStatus());
2499  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2500 
2501  // ReadTOC doesn't error out if the tray is open, and it completes rather quickly in that case.
2502  //
2503  if(!CommandCheckDiscPresent())
2504   return(26000);
2505 
2506 
2507 
2508  // A gross approximation.
2509  // The penalty for the drive being stopped seems to be rather high(higher than what CalcSeekTime() currently introduces), although
2510  // that should be investigated further.
2511  //
2512  // ...and not to mention the time taken varies from disc to disc even!
2513  ret_time = 30000000 + CalcSeekTime(CurSector, 0, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
2514 
2515  SeekTarget = 0;
2516  HoldLogicalPos = false;
2517  DriveStatus = DS_PAUSED;	// Ends up in a pause state when the command is finished.  Maybe we should add DS_READTOC or something...
2518  ClearAIP();
2519 
2520  return ret_time;
2521 }
2522 
Command_ReadTOC_Part2(void)2523 int32 PS_CDC::Command_ReadTOC_Part2(void)
2524 {
2525  //if(!CommandCheckDiscPresent())
2526  // DriveStatus = DS_PAUSED;
2527 
2528  WriteResult(MakeStatus());
2529  WriteIRQ(CDCIRQ_COMPLETE);
2530 
2531  return(0);
2532 }
2533 
Command_0x1d(const int arg_count,const uint8 * args)2534 int32 PS_CDC::Command_0x1d(const int arg_count, const uint8 *args)
2535 {
2536  WriteResult(MakeStatus());
2537  WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2538  return(0);
2539 }
2540 
2541 const PS_CDC::CDC_CTEntry PS_CDC::Commands[0x20] =
2542 {
2543  { /* 0x00, */ 0, 0, NULL, NULL, NULL },
2544  { /* 0x01, */ 0, 0, "Nop", &PS_CDC::Command_Nop, NULL },
2545  { /* 0x02, */ 3, 3, "Setloc", &PS_CDC::Command_Setloc, NULL },
2546  { /* 0x03, */ 0, 1, "Play", &PS_CDC::Command_Play, NULL },
2547  { /* 0x04, */ 0, 0, "Forward", &PS_CDC::Command_Forward, NULL },
2548  { /* 0x05, */ 0, 0, "Backward", &PS_CDC::Command_Backward, NULL },
2549  { /* 0x06, */ 0, 0, "ReadN", &PS_CDC::Command_ReadN, NULL },
2550  { /* 0x07, */ 0, 0, "Standby", &PS_CDC::Command_Standby, &PS_CDC::Command_Standby_Part2 },
2551  { /* 0x08, */ 0, 0, "Stop", &PS_CDC::Command_Stop, &PS_CDC::Command_Stop_Part2 },
2552  { /* 0x09, */ 0, 0, "Pause", &PS_CDC::Command_Pause, &PS_CDC::Command_Pause_Part2 },
2553  { /* 0x0A, */ 0, 0, "Reset", &PS_CDC::Command_Reset, &PS_CDC::Command_Seek_PartN },
2554  { /* 0x0B, */ 0, 0, "Mute", &PS_CDC::Command_Mute, NULL },
2555  { /* 0x0C, */ 0, 0, "Demute", &PS_CDC::Command_Demute, NULL },
2556  { /* 0x0D, */ 2, 2, "Setfilter", &PS_CDC::Command_Setfilter, NULL },
2557  { /* 0x0E, */ 1, 1, "Setmode", &PS_CDC::Command_Setmode, NULL },
2558  { /* 0x0F, */ 0, 0, "Getparam", &PS_CDC::Command_Getparam, NULL },
2559  { /* 0x10, */ 0, 0, "GetlocL", &PS_CDC::Command_GetlocL, NULL },
2560  { /* 0x11, */ 0, 0, "GetlocP", &PS_CDC::Command_GetlocP, NULL },
2561  { /* 0x12, */ 1, 1, "ReadT", &PS_CDC::Command_ReadT, &PS_CDC::Command_ReadT_Part2 },
2562  { /* 0x13, */ 0, 0, "GetTN", &PS_CDC::Command_GetTN, NULL },
2563  { /* 0x14, */ 1, 1, "GetTD", &PS_CDC::Command_GetTD, NULL },
2564  { /* 0x15, */ 0, 0, "SeekL", &PS_CDC::Command_SeekL, &PS_CDC::Command_Seek_PartN },
2565  { /* 0x16, */ 0, 0, "SeekP", &PS_CDC::Command_SeekP, &PS_CDC::Command_Seek_PartN },
2566 
2567  { /* 0x17, */ 0, 0, NULL, NULL, NULL },
2568  { /* 0x18, */ 0, 0, NULL, NULL, NULL },
2569 
2570  { /* 0x19, */ 1, 1/* ??? */, "Test", &PS_CDC::Command_Test, NULL },
2571  { /* 0x1A, */ 0, 0, "ID", &PS_CDC::Command_ID, &PS_CDC::Command_ID_Part2 },
2572  { /* 0x1B, */ 0, 0, "ReadS", &PS_CDC::Command_ReadS, NULL },
2573  { /* 0x1C, */ 0, 0, "Init", &PS_CDC::Command_Init, NULL },
2574  { /* 0x1D, */ 2, 2, "Unknown 0x1D", &PS_CDC::Command_0x1d, NULL },
2575  { /* 0x1E, */ 0, 0, "ReadTOC", &PS_CDC::Command_ReadTOC, &PS_CDC::Command_ReadTOC_Part2 },
2576  { /* 0x1F, */ 0, 0, NULL, NULL, NULL },
2577 };
2578 
2579 
2580 }
2581