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