10fc61562ee7d250a98e1d3a20a5654087b7b2ab
[pcsx_rearmed.git] / libpcsxcore / cdrom.c
1 /***************************************************************************
2  *   Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team              *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
18  ***************************************************************************/
19
20 /*
21 * Handles all CD-ROM registers and functions.
22 */
23
24 #include <assert.h>
25 #include "cdrom.h"
26 #include "ppf.h"
27 #include "psxdma.h"
28 #include "arm_features.h"
29
30 /* logging */
31 #if 0
32 #define CDR_LOG SysPrintf
33 #else
34 #define CDR_LOG(...)
35 #endif
36 #if 0
37 #define CDR_LOG_I SysPrintf
38 #else
39 #define CDR_LOG_I log_unhandled
40 #endif
41 #if 0
42 #define CDR_LOG_IO SysPrintf
43 #else
44 #define CDR_LOG_IO(...)
45 #endif
46 //#define CDR_LOG_CMD_IRQ
47
48 static struct {
49         // unused members maintain savesate compatibility
50         unsigned char unused0;
51         unsigned char unused1;
52         unsigned char Reg2;
53         unsigned char unused2;
54         unsigned char Ctrl;
55         unsigned char Stat;
56
57         unsigned char StatP;
58
59         unsigned char Transfer[DATA_SIZE];
60         struct {
61                 unsigned char Track;
62                 unsigned char Index;
63                 unsigned char Relative[3];
64                 unsigned char Absolute[3];
65         } subq;
66         unsigned char TrackChanged;
67         unsigned char unused3[3];
68         unsigned int  freeze_ver;
69
70         unsigned char Prev[4];
71         unsigned char Param[8];
72         unsigned char Result[16];
73
74         unsigned char ParamC;
75         unsigned char ParamP;
76         unsigned char ResultC;
77         unsigned char ResultP;
78         unsigned char ResultReady;
79         unsigned char Cmd;
80         unsigned char SubqForwardSectors;
81         unsigned char SetlocPending;
82         u32 Reading;
83
84         unsigned char ResultTN[6];
85         unsigned char ResultTD[4];
86         unsigned char SetSectorPlay[4];
87         unsigned char SetSectorEnd[4];
88         unsigned char SetSector[4];
89         unsigned char Track;
90         boolean Play, Muted;
91         int CurTrack;
92         int Mode, File, Channel;
93         unsigned char LocL[8];
94         int FirstSector;
95
96         xa_decode_t Xa;
97
98         u16 FifoOffset;
99         u16 FifoSize;
100
101         u16 CmdInProgress;
102         u8 Irq1Pending;
103         u8 unused5;
104         u32 unused6;
105
106         u8 unused7;
107
108         u8 DriveState;
109         u8 FastForward;
110         u8 FastBackward;
111         u8 unused8;
112
113         u8 AttenuatorLeftToLeft, AttenuatorLeftToRight;
114         u8 AttenuatorRightToRight, AttenuatorRightToLeft;
115         u8 AttenuatorLeftToLeftT, AttenuatorLeftToRightT;
116         u8 AttenuatorRightToRightT, AttenuatorRightToLeftT;
117 } cdr;
118 static s16 read_buf[CD_FRAMESIZE_RAW/2];
119
120 /* CD-ROM magic numbers */
121 #define CdlSync        0  /* nocash documentation : "Uh, actually, returns error code 40h = Invalid Command...?" */
122 #define CdlNop         1
123 #define CdlSetloc      2
124 #define CdlPlay        3
125 #define CdlForward     4
126 #define CdlBackward    5
127 #define CdlReadN       6
128 #define CdlStandby     7
129 #define CdlStop        8
130 #define CdlPause       9
131 #define CdlReset       10
132 #define CdlMute        11
133 #define CdlDemute      12
134 #define CdlSetfilter   13
135 #define CdlSetmode     14
136 #define CdlGetparam    15
137 #define CdlGetlocL     16
138 #define CdlGetlocP     17
139 #define CdlReadT       18
140 #define CdlGetTN       19
141 #define CdlGetTD       20
142 #define CdlSeekL       21
143 #define CdlSeekP       22
144 #define CdlSetclock    23
145 #define CdlGetclock    24
146 #define CdlTest        25
147 #define CdlID          26
148 #define CdlReadS       27
149 #define CdlInit        28
150 #define CdlGetQ        29
151 #define CdlReadToc     30
152
153 #ifdef CDR_LOG_CMD_IRQ
154 static const char * const CmdName[0x100] = {
155     "CdlSync",     "CdlNop",       "CdlSetloc",  "CdlPlay",
156     "CdlForward",  "CdlBackward",  "CdlReadN",   "CdlStandby",
157     "CdlStop",     "CdlPause",     "CdlReset",    "CdlMute",
158     "CdlDemute",   "CdlSetfilter", "CdlSetmode", "CdlGetparam",
159     "CdlGetlocL",  "CdlGetlocP",   "CdlReadT",   "CdlGetTN",
160     "CdlGetTD",    "CdlSeekL",     "CdlSeekP",   "CdlSetclock",
161     "CdlGetclock", "CdlTest",      "CdlID",      "CdlReadS",
162     "CdlInit",     NULL,           "CDlReadToc", NULL
163 };
164 #endif
165
166 unsigned char Test04[] = { 0 };
167 unsigned char Test05[] = { 0 };
168 unsigned char Test20[] = { 0x98, 0x06, 0x10, 0xC3 };
169 unsigned char Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F };
170 unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
171
172 // cdr.Stat:
173 #define NoIntr          0
174 #define DataReady       1
175 #define Complete        2
176 #define Acknowledge     3
177 #define DataEnd         4
178 #define DiskError       5
179
180 /* Modes flags */
181 #define MODE_SPEED       (1<<7) // 0x80
182 #define MODE_STRSND      (1<<6) // 0x40 ADPCM on/off
183 #define MODE_SIZE_2340   (1<<5) // 0x20
184 #define MODE_SIZE_2328   (1<<4) // 0x10
185 #define MODE_SIZE_2048   (0<<4) // 0x00
186 #define MODE_SF          (1<<3) // 0x08 channel on/off
187 #define MODE_REPORT      (1<<2) // 0x04
188 #define MODE_AUTOPAUSE   (1<<1) // 0x02
189 #define MODE_CDDA        (1<<0) // 0x01
190
191 /* Status flags */
192 #define STATUS_PLAY      (1<<7) // 0x80
193 #define STATUS_SEEK      (1<<6) // 0x40
194 #define STATUS_READ      (1<<5) // 0x20
195 #define STATUS_SHELLOPEN (1<<4) // 0x10
196 #define STATUS_UNKNOWN3  (1<<3) // 0x08
197 #define STATUS_UNKNOWN2  (1<<2) // 0x04
198 #define STATUS_ROTATING  (1<<1) // 0x02
199 #define STATUS_ERROR     (1<<0) // 0x01
200
201 /* Errors */
202 #define ERROR_NOTREADY   (1<<7) // 0x80
203 #define ERROR_INVALIDCMD (1<<6) // 0x40
204 #define ERROR_INVALIDARG (1<<5) // 0x20
205
206 // 1x = 75 sectors per second
207 // PSXCLK = 1 sec in the ps
208 // so (PSXCLK / 75) = cdr read time (linuzappz)
209 #define cdReadTime (PSXCLK / 75)
210
211 #define LOCL_INVALID 0xff
212 #define SUBQ_FORWARD_SECTORS 2u
213
214 enum drive_state {
215         DRIVESTATE_STANDBY = 0, // pause, play, read
216         DRIVESTATE_LID_OPEN,
217         DRIVESTATE_RESCAN_CD,
218         DRIVESTATE_PREPARE_CD,
219         DRIVESTATE_STOPPED,
220 };
221
222 static struct CdrStat stat;
223
224 static unsigned int msf2sec(const u8 *msf) {
225         return ((msf[0] * 60 + msf[1]) * 75) + msf[2];
226 }
227
228 // for that weird psemu API..
229 static unsigned int fsm2sec(const u8 *msf) {
230         return ((msf[2] * 60 + msf[1]) * 75) + msf[0];
231 }
232
233 static void sec2msf(unsigned int s, u8 *msf) {
234         msf[0] = s / 75 / 60;
235         s = s - msf[0] * 75 * 60;
236         msf[1] = s / 75;
237         s = s - msf[1] * 75;
238         msf[2] = s;
239 }
240
241 // cdrInterrupt
242 #define CDR_INT(eCycle) { \
243         psxRegs.interrupt |= (1 << PSXINT_CDR); \
244         psxRegs.intCycle[PSXINT_CDR].cycle = eCycle; \
245         psxRegs.intCycle[PSXINT_CDR].sCycle = psxRegs.cycle; \
246         new_dyna_set_event(PSXINT_CDR, eCycle); \
247 }
248
249 // cdrPlayReadInterrupt
250 #define CDRPLAYREAD_INT(eCycle, isFirst) { \
251         u32 e_ = eCycle; \
252         psxRegs.interrupt |= (1 << PSXINT_CDREAD); \
253         if (isFirst) \
254                 psxRegs.intCycle[PSXINT_CDREAD].sCycle = psxRegs.cycle; \
255         else \
256                 psxRegs.intCycle[PSXINT_CDREAD].sCycle += psxRegs.intCycle[PSXINT_CDREAD].cycle; \
257         psxRegs.intCycle[PSXINT_CDREAD].cycle = e_; \
258         new_dyna_set_event_abs(PSXINT_CDREAD, psxRegs.intCycle[PSXINT_CDREAD].sCycle + e_); \
259 }
260
261 // cdrLidSeekInterrupt
262 #define CDRLID_INT(eCycle) { \
263         psxRegs.interrupt |= (1 << PSXINT_CDRLID); \
264         psxRegs.intCycle[PSXINT_CDRLID].cycle = eCycle; \
265         psxRegs.intCycle[PSXINT_CDRLID].sCycle = psxRegs.cycle; \
266         new_dyna_set_event(PSXINT_CDRLID, eCycle); \
267 }
268
269 #define StopReading() { \
270         cdr.Reading = 0; \
271         psxRegs.interrupt &= ~(1 << PSXINT_CDREAD); \
272 }
273
274 #define StopCdda() { \
275         if (cdr.Play && !Config.Cdda) CDR_stop(); \
276         cdr.Play = FALSE; \
277         cdr.FastForward = 0; \
278         cdr.FastBackward = 0; \
279 }
280
281 #define SetPlaySeekRead(x, f) { \
282         x &= ~(STATUS_PLAY | STATUS_SEEK | STATUS_READ); \
283         x |= f; \
284 }
285
286 #define SetResultSize(size) { \
287         cdr.ResultP = 0; \
288         cdr.ResultC = size; \
289         cdr.ResultReady = 1; \
290 }
291
292 static void setIrq(int log_cmd)
293 {
294         if (cdr.Stat & cdr.Reg2)
295                 psxHu32ref(0x1070) |= SWAP32((u32)0x4);
296
297 #ifdef CDR_LOG_CMD_IRQ
298         if (cdr.Stat)
299         {
300                 int i;
301                 SysPrintf("%u cdrom: CDR IRQ=%d cmd %02x stat %02x: ",
302                         psxRegs.cycle, !!(cdr.Stat & cdr.Reg2), log_cmd, cdr.Stat);
303                 for (i = 0; i < cdr.ResultC; i++)
304                         SysPrintf("%02x ", cdr.Result[i]);
305                 SysPrintf("\n");
306         }
307 #endif
308 }
309
310 // timing used in this function was taken from tests on real hardware
311 // (yes it's slow, but you probably don't want to modify it)
312 void cdrLidSeekInterrupt(void)
313 {
314         CDR_LOG_I("%u %s cdr.DriveState=%d\n", psxRegs.cycle, __func__, cdr.DriveState);
315
316         switch (cdr.DriveState) {
317         default:
318         case DRIVESTATE_STANDBY:
319                 StopCdda();
320                 StopReading();
321                 SetPlaySeekRead(cdr.StatP, 0);
322
323                 if (CDR_getStatus(&stat) == -1)
324                         return;
325
326                 if (stat.Status & STATUS_SHELLOPEN)
327                 {
328                         memset(cdr.Prev, 0xff, sizeof(cdr.Prev));
329                         cdr.DriveState = DRIVESTATE_LID_OPEN;
330                         CDRLID_INT(0x800);
331                 }
332                 break;
333
334         case DRIVESTATE_LID_OPEN:
335                 if (CDR_getStatus(&stat) == -1)
336                         stat.Status &= ~STATUS_SHELLOPEN;
337
338                 // 02, 12, 10
339                 if (!(cdr.StatP & STATUS_SHELLOPEN)) {
340                         cdr.StatP |= STATUS_SHELLOPEN;
341
342                         // could generate error irq here, but real hardware
343                         // only sometimes does that
344                         // (not done when lots of commands are sent?)
345
346                         CDRLID_INT(cdReadTime * 30);
347                         break;
348                 }
349                 else if (cdr.StatP & STATUS_ROTATING) {
350                         cdr.StatP &= ~STATUS_ROTATING;
351                 }
352                 else if (!(stat.Status & STATUS_SHELLOPEN)) {
353                         // closed now
354                         CheckCdrom();
355
356                         // cdr.StatP STATUS_SHELLOPEN is "sticky"
357                         // and is only cleared by CdlNop
358
359                         cdr.DriveState = DRIVESTATE_RESCAN_CD;
360                         CDRLID_INT(cdReadTime * 105);
361                         break;
362                 }
363
364                 // recheck for close
365                 CDRLID_INT(cdReadTime * 3);
366                 break;
367
368         case DRIVESTATE_RESCAN_CD:
369                 cdr.StatP |= STATUS_ROTATING;
370                 cdr.DriveState = DRIVESTATE_PREPARE_CD;
371
372                 // this is very long on real hardware, over 6 seconds
373                 // make it a bit faster here...
374                 CDRLID_INT(cdReadTime * 150);
375                 break;
376
377         case DRIVESTATE_PREPARE_CD:
378                 if (cdr.StatP & STATUS_SEEK) {
379                         SetPlaySeekRead(cdr.StatP, 0);
380                         cdr.DriveState = DRIVESTATE_STANDBY;
381                 }
382                 else {
383                         SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
384                         CDRLID_INT(cdReadTime * 26);
385                 }
386                 break;
387         }
388 }
389
390 static void Find_CurTrack(const u8 *time)
391 {
392         int current, sect;
393
394         current = msf2sec(time);
395
396         for (cdr.CurTrack = 1; cdr.CurTrack < cdr.ResultTN[1]; cdr.CurTrack++) {
397                 CDR_getTD(cdr.CurTrack + 1, cdr.ResultTD);
398                 sect = fsm2sec(cdr.ResultTD);
399                 if (sect - current >= 150)
400                         break;
401         }
402 }
403
404 static void generate_subq(const u8 *time)
405 {
406         unsigned char start[3], next[3];
407         unsigned int this_s, start_s, next_s, pregap;
408         int relative_s;
409
410         CDR_getTD(cdr.CurTrack, start);
411         if (cdr.CurTrack + 1 <= cdr.ResultTN[1]) {
412                 pregap = 150;
413                 CDR_getTD(cdr.CurTrack + 1, next);
414         }
415         else {
416                 // last track - cd size
417                 pregap = 0;
418                 next[0] = cdr.SetSectorEnd[2];
419                 next[1] = cdr.SetSectorEnd[1];
420                 next[2] = cdr.SetSectorEnd[0];
421         }
422
423         this_s = msf2sec(time);
424         start_s = fsm2sec(start);
425         next_s = fsm2sec(next);
426
427         cdr.TrackChanged = FALSE;
428
429         if (next_s - this_s < pregap) {
430                 cdr.TrackChanged = TRUE;
431                 cdr.CurTrack++;
432                 start_s = next_s;
433         }
434
435         cdr.subq.Index = 1;
436
437         relative_s = this_s - start_s;
438         if (relative_s < 0) {
439                 cdr.subq.Index = 0;
440                 relative_s = -relative_s;
441         }
442         sec2msf(relative_s, cdr.subq.Relative);
443
444         cdr.subq.Track = itob(cdr.CurTrack);
445         cdr.subq.Relative[0] = itob(cdr.subq.Relative[0]);
446         cdr.subq.Relative[1] = itob(cdr.subq.Relative[1]);
447         cdr.subq.Relative[2] = itob(cdr.subq.Relative[2]);
448         cdr.subq.Absolute[0] = itob(time[0]);
449         cdr.subq.Absolute[1] = itob(time[1]);
450         cdr.subq.Absolute[2] = itob(time[2]);
451 }
452
453 static int ReadTrack(const u8 *time)
454 {
455         unsigned char tmp[3];
456         int read_ok;
457
458         tmp[0] = itob(time[0]);
459         tmp[1] = itob(time[1]);
460         tmp[2] = itob(time[2]);
461
462         if (memcmp(cdr.Prev, tmp, 3) == 0)
463                 return 1;
464
465         CDR_LOG("ReadTrack *** %02x:%02x:%02x\n", tmp[0], tmp[1], tmp[2]);
466
467         read_ok = CDR_readTrack(tmp);
468         if (read_ok)
469                 memcpy(cdr.Prev, tmp, 3);
470         return read_ok;
471 }
472
473 static void UpdateSubq(const u8 *time)
474 {
475         const struct SubQ *subq;
476         u16 crc;
477
478         if (CheckSBI(time))
479                 return;
480
481         subq = (struct SubQ *)CDR_getBufferSub(MSF2SECT(time[0], time[1], time[2]));
482         if (subq != NULL && cdr.CurTrack == 1) {
483                 crc = calcCrc((u8 *)subq + 12, 10);
484                 if (crc == (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
485                         cdr.subq.Track = subq->TrackNumber;
486                         cdr.subq.Index = subq->IndexNumber;
487                         memcpy(cdr.subq.Relative, subq->TrackRelativeAddress, 3);
488                         memcpy(cdr.subq.Absolute, subq->AbsoluteAddress, 3);
489                 }
490                 else {
491                         CDR_LOG_I("subq bad crc @%02d:%02d:%02d\n",
492                                 time[0], time[1], time[2]);
493                 }
494         }
495         else {
496                 generate_subq(time);
497         }
498
499         CDR_LOG(" -> %02x,%02x %02x:%02x:%02x %02x:%02x:%02x\n",
500                 cdr.subq.Track, cdr.subq.Index,
501                 cdr.subq.Relative[0], cdr.subq.Relative[1], cdr.subq.Relative[2],
502                 cdr.subq.Absolute[0], cdr.subq.Absolute[1], cdr.subq.Absolute[2]);
503 }
504
505 static void cdrPlayInterrupt_Autopause()
506 {
507         u32 abs_lev_max = 0;
508         boolean abs_lev_chselect;
509         u32 i;
510
511         if ((cdr.Mode & MODE_AUTOPAUSE) && cdr.TrackChanged) {
512                 CDR_LOG( "CDDA STOP\n" );
513
514                 // Magic the Gathering
515                 // - looping territory cdda
516
517                 // ...?
518                 //cdr.ResultReady = 1;
519                 //cdr.Stat = DataReady;
520                 cdr.Stat = DataEnd;
521                 setIrq(0x1000); // 0x1000 just for logging purposes
522
523                 StopCdda();
524                 SetPlaySeekRead(cdr.StatP, 0);
525         }
526         else if (((cdr.Mode & MODE_REPORT) || cdr.FastForward || cdr.FastBackward)) {
527                 cdr.Result[0] = cdr.StatP;
528                 cdr.Result[1] = cdr.subq.Track;
529                 cdr.Result[2] = cdr.subq.Index;
530                 
531                 abs_lev_chselect = cdr.subq.Absolute[1] & 0x01;
532                 
533                 /* 8 is a hack. For accuracy, it should be 588. */
534                 for (i = 0; i < 8; i++)
535                 {
536                         abs_lev_max = MAX_VALUE(abs_lev_max, abs(read_buf[i * 2 + abs_lev_chselect]));
537                 }
538                 abs_lev_max = MIN_VALUE(abs_lev_max, 32767);
539                 abs_lev_max |= abs_lev_chselect << 15;
540
541                 if (cdr.subq.Absolute[2] & 0x10) {
542                         cdr.Result[3] = cdr.subq.Relative[0];
543                         cdr.Result[4] = cdr.subq.Relative[1] | 0x80;
544                         cdr.Result[5] = cdr.subq.Relative[2];
545                 }
546                 else {
547                         cdr.Result[3] = cdr.subq.Absolute[0];
548                         cdr.Result[4] = cdr.subq.Absolute[1];
549                         cdr.Result[5] = cdr.subq.Absolute[2];
550                 }
551
552                 cdr.Result[6] = abs_lev_max >> 0;
553                 cdr.Result[7] = abs_lev_max >> 8;
554
555                 // Rayman: Logo freeze (resultready + dataready)
556                 cdr.ResultReady = 1;
557                 cdr.Stat = DataReady;
558
559                 SetResultSize(8);
560                 setIrq(0x1001);
561         }
562 }
563
564 static int cdrSeekTime(unsigned char *target)
565 {
566         int diff = msf2sec(cdr.SetSectorPlay) - msf2sec(target);
567         int seekTime = abs(diff) * (cdReadTime / 200);
568         /*
569         * Gameblabla :
570         * It was originally set to 1000000 for Driver, however it is not high enough for Worms Pinball
571         * and was unreliable for that game.
572         * I also tested it against Mednafen and Driver's titlescreen music starts 25 frames later, not immediatly.
573         *
574         * Obviously, this isn't perfect but right now, it should be a bit better.
575         * Games to test this against if you change that setting :
576         * - Driver (titlescreen music delay and retry mission)
577         * - Worms Pinball (Will either not boot or crash in the memory card screen)
578         * - Viewpoint (short pauses if the delay in the ingame music is too long)
579         *
580         * It seems that 3386880 * 5 is too much for Driver's titlescreen and it starts skipping.
581         * However, 1000000 is not enough for Worms Pinball to reliably boot.
582         */
583         if(seekTime > 3386880 * 2) seekTime = 3386880 * 2;
584         CDR_LOG("seek: %.2f %.2f\n", (float)seekTime / PSXCLK, (float)seekTime / cdReadTime);
585         return seekTime;
586 }
587
588 static u32 cdrAlignTimingHack(u32 cycles)
589 {
590         /*
591          * timing hack for T'ai Fu - Wrath of the Tiger:
592          * The game has a bug where it issues some cdc commands from a low priority
593          * vint handler, however there is a higher priority default bios handler
594          * that acks the vint irq and returns, so game's handler is not reached
595          * (see bios irq handler chains at e004 and the game's irq handling func
596          * at 80036810). For the game to work, vint has to arrive after the bios
597          * vint handler rejects some other irq (of which only cd and rcnt2 are
598          * active), but before the game's handler loop reads I_STAT. The time
599          * window for this is quite small (~1k cycles of so). Apparently this
600          * somehow happens naturally on the real hardware.
601          *
602          * Note: always enforcing this breaks other games like Crash PAL version
603          * (inputs get dropped because bios handler doesn't see interrupts).
604          */
605         u32 vint_rel;
606         if (psxRegs.cycle - rcnts[3].cycleStart > 250000)
607                 return cycles;
608         vint_rel = rcnts[3].cycleStart + 63000 - psxRegs.cycle;
609         vint_rel += PSXCLK / 60;
610         while ((s32)(vint_rel - cycles) < 0)
611                 vint_rel += PSXCLK / 60;
612         return vint_rel;
613 }
614
615 static void cdrUpdateTransferBuf(const u8 *buf);
616 static void cdrReadInterrupt(void);
617 static void cdrPrepCdda(s16 *buf, int samples);
618 static void cdrAttenuate(s16 *buf, int samples, int stereo);
619
620 static void msfiAdd(u8 *msfi, u32 count)
621 {
622         assert(count < 75);
623         msfi[2] += count;
624         if (msfi[2] >= 75) {
625                 msfi[2] -= 75;
626                 msfi[1]++;
627                 if (msfi[1] == 60) {
628                         msfi[1] = 0;
629                         msfi[0]++;
630                 }
631         }
632 }
633
634 void cdrPlayReadInterrupt(void)
635 {
636         if (cdr.Reading) {
637                 cdrReadInterrupt();
638                 return;
639         }
640
641         if (!cdr.Play) return;
642
643         CDR_LOG( "CDDA - %d:%d:%d\n",
644                 cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2] );
645
646         SetPlaySeekRead(cdr.StatP, STATUS_PLAY);
647         if (memcmp(cdr.SetSectorPlay, cdr.SetSectorEnd, 3) == 0) {
648                 StopCdda();
649                 SetPlaySeekRead(cdr.StatP, 0);
650                 cdr.TrackChanged = TRUE;
651         }
652         else {
653                 CDR_readCDDA(cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2], (u8 *)read_buf);
654         }
655
656         if (!cdr.Stat && (cdr.Mode & (MODE_AUTOPAUSE|MODE_REPORT)))
657                 cdrPlayInterrupt_Autopause();
658
659         if (!cdr.Muted && !Config.Cdda) {
660                 cdrPrepCdda(read_buf, CD_FRAMESIZE_RAW / 4);
661                 cdrAttenuate(read_buf, CD_FRAMESIZE_RAW / 4, 1);
662                 SPU_playCDDAchannel(read_buf, CD_FRAMESIZE_RAW, psxRegs.cycle, cdr.FirstSector);
663                 cdr.FirstSector = 0;
664         }
665
666         msfiAdd(cdr.SetSectorPlay, 1);
667
668         // update for CdlGetlocP/autopause
669         generate_subq(cdr.SetSectorPlay);
670
671         CDRPLAYREAD_INT(cdReadTime, 0);
672 }
673
674 #define CMD_PART2           0x100
675 #define CMD_WHILE_NOT_READY 0x200
676
677 void cdrInterrupt(void) {
678         int start_rotating = 0;
679         int error = 0;
680         u32 cycles, seekTime = 0;
681         u32 second_resp_time = 0;
682         const void *buf;
683         u8 ParamC;
684         u8 set_loc[3];
685         int read_ok;
686         u16 not_ready = 0;
687         u16 Cmd;
688         int i;
689
690         if (cdr.Stat) {
691                 CDR_LOG_I("%u cdrom: cmd %02x with irqstat %x\n",
692                         psxRegs.cycle, cdr.CmdInProgress, cdr.Stat);
693                 return;
694         }
695         if (cdr.Irq1Pending) {
696                 // hand out the "newest" sector, according to nocash
697                 cdrUpdateTransferBuf(CDR_getBuffer());
698                 CDR_LOG_I("cdrom: %x:%02x:%02x loaded on ack\n",
699                         cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
700                 SetResultSize(1);
701                 cdr.Result[0] = cdr.Irq1Pending;
702                 cdr.Stat = (cdr.Irq1Pending & STATUS_ERROR) ? DiskError : DataReady;
703                 cdr.Irq1Pending = 0;
704                 setIrq(0x1003);
705                 return;
706         }
707
708         // default response
709         SetResultSize(1);
710         cdr.Result[0] = cdr.StatP;
711         cdr.Stat = Acknowledge;
712
713         Cmd = cdr.CmdInProgress;
714         cdr.CmdInProgress = 0;
715         ParamC = cdr.ParamC;
716
717         if (Cmd < 0x100) {
718                 cdr.Ctrl &= ~0x80;
719                 cdr.ParamC = 0;
720                 cdr.Cmd = 0;
721         }
722
723         switch (cdr.DriveState) {
724         case DRIVESTATE_PREPARE_CD:
725                 if (Cmd > 2) {
726                         // Syphon filter 2 expects commands to work shortly after it sees
727                         // STATUS_ROTATING, so give up trying to emulate the startup seq
728                         cdr.DriveState = DRIVESTATE_STANDBY;
729                         cdr.StatP &= ~STATUS_SEEK;
730                         psxRegs.interrupt &= ~(1 << PSXINT_CDRLID);
731                         break;
732                 }
733                 // fallthrough
734         case DRIVESTATE_LID_OPEN:
735         case DRIVESTATE_RESCAN_CD:
736                 // no disk or busy with the initial scan, allowed cmds are limited
737                 not_ready = CMD_WHILE_NOT_READY;
738                 break;
739         }
740
741         switch (Cmd | not_ready) {
742                 case CdlNop:
743                 case CdlNop + CMD_WHILE_NOT_READY:
744                         if (cdr.DriveState != DRIVESTATE_LID_OPEN)
745                                 cdr.StatP &= ~STATUS_SHELLOPEN;
746                         break;
747
748                 case CdlSetloc:
749                 case CdlSetloc + CMD_WHILE_NOT_READY:
750                         CDR_LOG("CDROM setloc command (%02X, %02X, %02X)\n", cdr.Param[0], cdr.Param[1], cdr.Param[2]);
751
752                         // MM must be BCD, SS must be BCD and <0x60, FF must be BCD and <0x75
753                         if (((cdr.Param[0] & 0x0F) > 0x09) || (cdr.Param[0] > 0x99) || ((cdr.Param[1] & 0x0F) > 0x09) || (cdr.Param[1] >= 0x60) || ((cdr.Param[2] & 0x0F) > 0x09) || (cdr.Param[2] >= 0x75))
754                         {
755                                 CDR_LOG_I("Invalid/out of range seek to %02X:%02X:%02X\n", cdr.Param[0], cdr.Param[1], cdr.Param[2]);
756                                 error = ERROR_INVALIDARG;
757                                 goto set_error;
758                         }
759                         else
760                         {
761                                 for (i = 0; i < 3; i++)
762                                         set_loc[i] = btoi(cdr.Param[i]);
763                                 memcpy(cdr.SetSector, set_loc, 3);
764                                 cdr.SetSector[3] = 0;
765                                 cdr.SetlocPending = 1;
766                         }
767                         break;
768
769                 do_CdlPlay:
770                 case CdlPlay:
771                         StopCdda();
772                         StopReading();
773
774                         cdr.FastBackward = 0;
775                         cdr.FastForward = 0;
776
777                         // BIOS CD Player
778                         // - Pause player, hit Track 01/02/../xx (Setloc issued!!)
779
780                         if (ParamC != 0 && cdr.Param[0] != 0) {
781                                 int track = btoi( cdr.Param[0] );
782
783                                 if (track <= cdr.ResultTN[1])
784                                         cdr.CurTrack = track;
785
786                                 CDR_LOG("PLAY track %d\n", cdr.CurTrack);
787
788                                 if (CDR_getTD((u8)cdr.CurTrack, cdr.ResultTD) != -1) {
789                                         for (i = 0; i < 3; i++)
790                                                 set_loc[i] = cdr.ResultTD[2 - i];
791                                         seekTime = cdrSeekTime(set_loc);
792                                         memcpy(cdr.SetSectorPlay, set_loc, 3);
793                                 }
794                         }
795                         else if (cdr.SetlocPending) {
796                                 seekTime = cdrSeekTime(cdr.SetSector);
797                                 memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
798                         }
799                         else {
800                                 CDR_LOG("PLAY Resume @ %d:%d:%d\n",
801                                         cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2]);
802                         }
803                         cdr.SetlocPending = 0;
804
805                         /*
806                         Rayman: detect track changes
807                         - fixes logo freeze
808
809                         Twisted Metal 2: skip PREGAP + starting accurate SubQ
810                         - plays tracks without retry play
811
812                         Wild 9: skip PREGAP + starting accurate SubQ
813                         - plays tracks without retry play
814                         */
815                         Find_CurTrack(cdr.SetSectorPlay);
816                         generate_subq(cdr.SetSectorPlay);
817                         cdr.LocL[0] = LOCL_INVALID;
818                         cdr.SubqForwardSectors = 1;
819                         cdr.TrackChanged = FALSE;
820                         cdr.FirstSector = 1;
821
822                         if (!Config.Cdda)
823                                 CDR_play(cdr.SetSectorPlay);
824
825                         SetPlaySeekRead(cdr.StatP, STATUS_SEEK | STATUS_ROTATING);
826                         
827                         // BIOS player - set flag again
828                         cdr.Play = TRUE;
829
830                         CDRPLAYREAD_INT(cdReadTime + seekTime, 1);
831                         start_rotating = 1;
832                         break;
833
834                 case CdlForward:
835                         // TODO: error 80 if stopped
836                         cdr.Stat = Complete;
837
838                         // GameShark CD Player: Calls 2x + Play 2x
839                         cdr.FastForward = 1;
840                         cdr.FastBackward = 0;
841                         break;
842
843                 case CdlBackward:
844                         cdr.Stat = Complete;
845
846                         // GameShark CD Player: Calls 2x + Play 2x
847                         cdr.FastBackward = 1;
848                         cdr.FastForward = 0;
849                         break;
850
851                 case CdlStandby:
852                         if (cdr.DriveState != DRIVESTATE_STOPPED) {
853                                 error = ERROR_INVALIDARG;
854                                 goto set_error;
855                         }
856                         second_resp_time = cdReadTime * 125 / 2;
857                         start_rotating = 1;
858                         break;
859
860                 case CdlStandby + CMD_PART2:
861                         cdr.Stat = Complete;
862                         break;
863
864                 case CdlStop:
865                         if (cdr.Play) {
866                                 // grab time for current track
867                                 CDR_getTD((u8)(cdr.CurTrack), cdr.ResultTD);
868
869                                 cdr.SetSectorPlay[0] = cdr.ResultTD[2];
870                                 cdr.SetSectorPlay[1] = cdr.ResultTD[1];
871                                 cdr.SetSectorPlay[2] = cdr.ResultTD[0];
872                         }
873
874                         StopCdda();
875                         StopReading();
876                         SetPlaySeekRead(cdr.StatP, 0);
877                         cdr.StatP &= ~STATUS_ROTATING;
878                         cdr.LocL[0] = LOCL_INVALID;
879
880                         second_resp_time = 0x800;
881                         if (cdr.DriveState == DRIVESTATE_STANDBY)
882                                 second_resp_time = cdReadTime * 30 / 2;
883
884                         cdr.DriveState = DRIVESTATE_STOPPED;
885                         break;
886
887                 case CdlStop + CMD_PART2:
888                         cdr.Stat = Complete;
889                         break;
890
891                 case CdlPause:
892                         StopCdda();
893                         StopReading();
894                         /*
895                         Gundam Battle Assault 2: much slower (*)
896                         - Fixes boot, gameplay
897
898                         Hokuto no Ken 2: slower
899                         - Fixes intro + subtitles
900
901                         InuYasha - Feudal Fairy Tale: slower
902                         - Fixes battles
903                         */
904                         /* Gameblabla - Tightening the timings (as taken from Duckstation). 
905                          * The timings from Duckstation are based upon hardware tests.
906                          * Mednafen's timing don't work for Gundam Battle Assault 2 in PAL/50hz mode,
907                          * seems to be timing sensitive as it can depend on the CPU's clock speed.
908                          * */
909                         if (!(cdr.StatP & (STATUS_PLAY | STATUS_READ)))
910                         {
911                                 second_resp_time = 7000;
912                         }
913                         else
914                         {
915                                 second_resp_time = (((cdr.Mode & MODE_SPEED) ? 2 : 1) * 1000000);
916                         }
917                         SetPlaySeekRead(cdr.StatP, 0);
918                         break;
919
920                 case CdlPause + CMD_PART2:
921                         cdr.Stat = Complete;
922                         break;
923
924                 case CdlReset:
925                 case CdlReset + CMD_WHILE_NOT_READY:
926                         StopCdda();
927                         StopReading();
928                         SetPlaySeekRead(cdr.StatP, 0);
929                         cdr.LocL[0] = LOCL_INVALID;
930                         cdr.Muted = FALSE;
931                         cdr.Mode = 0x20; /* This fixes This is Football 2, Pooh's Party lockups */
932                         second_resp_time = not_ready ? 70000 : 4100000;
933                         start_rotating = 1;
934                         break;
935
936                 case CdlReset + CMD_PART2:
937                 case CdlReset + CMD_PART2 + CMD_WHILE_NOT_READY:
938                         cdr.Stat = Complete;
939                         break;
940
941                 case CdlMute:
942                         cdr.Muted = TRUE;
943                         break;
944
945                 case CdlDemute:
946                         cdr.Muted = FALSE;
947                         break;
948
949                 case CdlSetfilter:
950                         cdr.File = cdr.Param[0];
951                         cdr.Channel = cdr.Param[1];
952                         break;
953
954                 case CdlSetmode:
955                 case CdlSetmode + CMD_WHILE_NOT_READY:
956                         CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]);
957                         cdr.Mode = cdr.Param[0];
958                         break;
959
960                 case CdlGetparam:
961                 case CdlGetparam + CMD_WHILE_NOT_READY:
962                         /* Gameblabla : According to mednafen, Result size should be 5 and done this way. */
963                         SetResultSize(5);
964                         cdr.Result[1] = cdr.Mode;
965                         cdr.Result[2] = 0;
966                         cdr.Result[3] = cdr.File;
967                         cdr.Result[4] = cdr.Channel;
968                         break;
969
970                 case CdlGetlocL:
971                         if (cdr.LocL[0] == LOCL_INVALID) {
972                                 error = 0x80;
973                                 goto set_error;
974                         }
975                         SetResultSize(8);
976                         memcpy(cdr.Result, cdr.LocL, 8);
977                         break;
978
979                 case CdlGetlocP:
980                         SetResultSize(8);
981                         memcpy(&cdr.Result, &cdr.subq, 8);
982                         break;
983
984                 case CdlReadT: // SetSession?
985                         // really long
986                         second_resp_time = cdReadTime * 290 / 4;
987                         start_rotating = 1;
988                         break;
989
990                 case CdlReadT + CMD_PART2:
991                         cdr.Stat = Complete;
992                         break;
993
994                 case CdlGetTN:
995                         SetResultSize(3);
996                         if (CDR_getTN(cdr.ResultTN) == -1) {
997                                 cdr.Stat = DiskError;
998                                 cdr.Result[0] |= STATUS_ERROR;
999                         } else {
1000                                 cdr.Stat = Acknowledge;
1001                                 cdr.Result[1] = itob(cdr.ResultTN[0]);
1002                                 cdr.Result[2] = itob(cdr.ResultTN[1]);
1003                         }
1004                         break;
1005
1006                 case CdlGetTD:
1007                         cdr.Track = btoi(cdr.Param[0]);
1008                         SetResultSize(4);
1009                         if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) {
1010                                 cdr.Stat = DiskError;
1011                                 cdr.Result[0] |= STATUS_ERROR;
1012                         } else {
1013                                 cdr.Stat = Acknowledge;
1014                                 cdr.Result[0] = cdr.StatP;
1015                                 cdr.Result[1] = itob(cdr.ResultTD[2]);
1016                                 cdr.Result[2] = itob(cdr.ResultTD[1]);
1017                                 /* According to Nocash's documentation, the function doesn't care about ff.
1018                                  * This can be seen also in Mednafen's implementation. */
1019                                 //cdr.Result[3] = itob(cdr.ResultTD[0]);
1020                         }
1021                         break;
1022
1023                 case CdlSeekL:
1024                 case CdlSeekP:
1025                         StopCdda();
1026                         StopReading();
1027                         SetPlaySeekRead(cdr.StatP, STATUS_SEEK | STATUS_ROTATING);
1028
1029                         seekTime = cdrSeekTime(cdr.SetSector);
1030                         memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
1031                         /*
1032                         Crusaders of Might and Magic = 0.5x-4x
1033                         - fix cutscene speech start
1034
1035                         Eggs of Steel = 2x-?
1036                         - fix new game
1037
1038                         Medievil = ?-4x
1039                         - fix cutscene speech
1040
1041                         Rockman X5 = 0.5-4x
1042                         - fix capcom logo
1043                         */
1044                         second_resp_time = cdReadTime + seekTime;
1045                         start_rotating = 1;
1046                         break;
1047
1048                 case CdlSeekL + CMD_PART2:
1049                 case CdlSeekP + CMD_PART2:
1050                         SetPlaySeekRead(cdr.StatP, 0);
1051                         cdr.Result[0] = cdr.StatP;
1052                         cdr.Stat = Complete;
1053
1054                         Find_CurTrack(cdr.SetSectorPlay);
1055                         read_ok = ReadTrack(cdr.SetSectorPlay);
1056                         if (read_ok && (buf = CDR_getBuffer()))
1057                                 memcpy(cdr.LocL, buf, 8);
1058                         UpdateSubq(cdr.SetSectorPlay);
1059                         cdr.TrackChanged = FALSE;
1060                         break;
1061
1062                 case CdlTest:
1063                 case CdlTest + CMD_WHILE_NOT_READY:
1064                         switch (cdr.Param[0]) {
1065                                 case 0x20: // System Controller ROM Version
1066                                         SetResultSize(4);
1067                                         memcpy(cdr.Result, Test20, 4);
1068                                         break;
1069                                 case 0x22:
1070                                         SetResultSize(8);
1071                                         memcpy(cdr.Result, Test22, 4);
1072                                         break;
1073                                 case 0x23: case 0x24:
1074                                         SetResultSize(8);
1075                                         memcpy(cdr.Result, Test23, 4);
1076                                         break;
1077                         }
1078                         break;
1079
1080                 case CdlID:
1081                         second_resp_time = 20480;
1082                         break;
1083
1084                 case CdlID + CMD_PART2:
1085                         SetResultSize(8);
1086                         cdr.Result[0] = cdr.StatP;
1087                         cdr.Result[1] = 0;
1088                         cdr.Result[2] = 0;
1089                         cdr.Result[3] = 0;
1090
1091                         // 0x10 - audio | 0x40 - disk missing | 0x80 - unlicensed
1092                         if (CDR_getStatus(&stat) == -1 || stat.Type == 0 || stat.Type == 0xff) {
1093                                 cdr.Result[1] = 0xc0;
1094                         }
1095                         else {
1096                                 if (stat.Type == 2)
1097                                         cdr.Result[1] |= 0x10;
1098                                 if (CdromId[0] == '\0')
1099                                         cdr.Result[1] |= 0x80;
1100                         }
1101                         cdr.Result[0] |= (cdr.Result[1] >> 4) & 0x08;
1102
1103                         /* This adds the string "PCSX" in Playstation bios boot screen */
1104                         memcpy((char *)&cdr.Result[4], "PCSX", 4);
1105                         cdr.Stat = Complete;
1106                         break;
1107
1108                 case CdlInit:
1109                 case CdlInit + CMD_WHILE_NOT_READY:
1110                         StopCdda();
1111                         StopReading();
1112                         SetPlaySeekRead(cdr.StatP, 0);
1113                         // yes, it really sets STATUS_SHELLOPEN
1114                         cdr.StatP |= STATUS_SHELLOPEN;
1115                         cdr.DriveState = DRIVESTATE_RESCAN_CD;
1116                         CDRLID_INT(20480);
1117                         start_rotating = 1;
1118                         break;
1119
1120                 case CdlGetQ:
1121                 case CdlGetQ + CMD_WHILE_NOT_READY:
1122                         break;
1123
1124                 case CdlReadToc:
1125                 case CdlReadToc + CMD_WHILE_NOT_READY:
1126                         cdr.LocL[0] = LOCL_INVALID;
1127                         second_resp_time = cdReadTime * 180 / 4;
1128                         start_rotating = 1;
1129                         break;
1130
1131                 case CdlReadToc + CMD_PART2:
1132                 case CdlReadToc + CMD_PART2 + CMD_WHILE_NOT_READY:
1133                         cdr.Stat = Complete;
1134                         break;
1135
1136                 case CdlReadN:
1137                 case CdlReadS:
1138                         if (cdr.Reading && !cdr.SetlocPending)
1139                                 break;
1140
1141                         Find_CurTrack(cdr.SetlocPending ? cdr.SetSector : cdr.SetSectorPlay);
1142
1143                         if ((cdr.Mode & MODE_CDDA) && cdr.CurTrack > 1)
1144                                 // Read* acts as play for cdda tracks in cdda mode
1145                                 goto do_CdlPlay;
1146
1147                         StopCdda();
1148                         if (cdr.SetlocPending) {
1149                                 seekTime = cdrSeekTime(cdr.SetSector);
1150                                 memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
1151                                 cdr.SetlocPending = 0;
1152                         }
1153                         cdr.Reading = 1;
1154                         cdr.FirstSector = 1;
1155
1156                         // Fighting Force 2 - update subq time immediately
1157                         // - fixes new game
1158                         UpdateSubq(cdr.SetSectorPlay);
1159                         cdr.LocL[0] = LOCL_INVALID;
1160                         cdr.SubqForwardSectors = 1;
1161
1162                         cycles = (cdr.Mode & 0x80) ? cdReadTime : cdReadTime * 2;
1163                         cycles += seekTime;
1164                         if (Config.hacks.cdr_read_timing)
1165                                 cycles = cdrAlignTimingHack(cycles);
1166                         CDRPLAYREAD_INT(cycles, 1);
1167
1168                         SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
1169                         start_rotating = 1;
1170                         break;
1171
1172                 case CdlSync:
1173                 default:
1174                         error = ERROR_INVALIDCMD;
1175                         // FALLTHROUGH
1176
1177                 set_error:
1178                         CDR_LOG_I("cdrom: cmd %02x error %02x\n", Cmd, error);
1179                         SetResultSize(2);
1180                         cdr.Result[0] = cdr.StatP | STATUS_ERROR;
1181                         cdr.Result[1] = not_ready ? ERROR_NOTREADY : error;
1182                         cdr.Stat = DiskError;
1183                         break;
1184         }
1185
1186         if (cdr.DriveState == DRIVESTATE_STOPPED && start_rotating) {
1187                 cdr.DriveState = DRIVESTATE_STANDBY;
1188                 cdr.StatP |= STATUS_ROTATING;
1189         }
1190
1191         if (second_resp_time) {
1192                 cdr.CmdInProgress = Cmd | 0x100;
1193                 CDR_INT(second_resp_time);
1194         }
1195         else if (cdr.Cmd && cdr.Cmd != (Cmd & 0xff)) {
1196                 cdr.CmdInProgress = cdr.Cmd;
1197                 CDR_LOG_I("%u cdrom: cmd %02x came before %02x finished\n",
1198                         psxRegs.cycle, cdr.Cmd, Cmd);
1199         }
1200
1201         setIrq(Cmd);
1202 }
1203
1204 #ifdef HAVE_ARMV7
1205  #define ssat32_to_16(v) \
1206   asm("ssat %0,#16,%1" : "=r" (v) : "r" (v))
1207 #else
1208  #define ssat32_to_16(v) do { \
1209   if (v < -32768) v = -32768; \
1210   else if (v > 32767) v = 32767; \
1211  } while (0)
1212 #endif
1213
1214 static void cdrPrepCdda(s16 *buf, int samples)
1215 {
1216 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1217         int i;
1218         for (i = 0; i < samples; i++) {
1219                 buf[i * 2 + 0] = SWAP16(buf[i * 2 + 0]);
1220                 buf[i * 2 + 1] = SWAP16(buf[i * 2 + 1]);
1221         }
1222 #endif
1223 }
1224
1225 static void cdrAttenuate(s16 *buf, int samples, int stereo)
1226 {
1227         int i, l, r;
1228         int ll = cdr.AttenuatorLeftToLeft;
1229         int lr = cdr.AttenuatorLeftToRight;
1230         int rl = cdr.AttenuatorRightToLeft;
1231         int rr = cdr.AttenuatorRightToRight;
1232
1233         if (lr == 0 && rl == 0 && 0x78 <= ll && ll <= 0x88 && 0x78 <= rr && rr <= 0x88)
1234                 return;
1235
1236         if (!stereo && ll == 0x40 && lr == 0x40 && rl == 0x40 && rr == 0x40)
1237                 return;
1238
1239         if (stereo) {
1240                 for (i = 0; i < samples; i++) {
1241                         l = buf[i * 2];
1242                         r = buf[i * 2 + 1];
1243                         l = (l * ll + r * rl) >> 7;
1244                         r = (r * rr + l * lr) >> 7;
1245                         ssat32_to_16(l);
1246                         ssat32_to_16(r);
1247                         buf[i * 2] = l;
1248                         buf[i * 2 + 1] = r;
1249                 }
1250         }
1251         else {
1252                 for (i = 0; i < samples; i++) {
1253                         l = buf[i];
1254                         l = l * (ll + rl) >> 7;
1255                         //r = r * (rr + lr) >> 7;
1256                         ssat32_to_16(l);
1257                         //ssat32_to_16(r);
1258                         buf[i] = l;
1259                 }
1260         }
1261 }
1262
1263 static void cdrReadInterruptSetResult(unsigned char result)
1264 {
1265         if (cdr.Stat) {
1266                 CDR_LOG_I("cdrom: %d:%02d:%02d irq miss, cmd=%02x irqstat=%02x\n",
1267                         cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2],
1268                         cdr.CmdInProgress, cdr.Stat);
1269                 cdr.Irq1Pending = result;
1270                 return;
1271         }
1272         SetResultSize(1);
1273         cdr.Result[0] = result;
1274         cdr.Stat = (result & STATUS_ERROR) ? DiskError : DataReady;
1275         setIrq(0x1004);
1276 }
1277
1278 static void cdrUpdateTransferBuf(const u8 *buf)
1279 {
1280         if (!buf)
1281                 return;
1282         memcpy(cdr.Transfer, buf, DATA_SIZE);
1283         CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
1284         CDR_LOG("cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
1285         if (cdr.FifoOffset < 2048 + 12)
1286                 CDR_LOG("cdrom: FifoOffset(1) %d/%d\n", cdr.FifoOffset, cdr.FifoSize);
1287 }
1288
1289 static void cdrReadInterrupt(void)
1290 {
1291         u8 *buf = NULL, *hdr;
1292         u8 subqPos[3];
1293         int read_ok;
1294
1295         memcpy(subqPos, cdr.SetSectorPlay, sizeof(subqPos));
1296         msfiAdd(subqPos, cdr.SubqForwardSectors);
1297         UpdateSubq(subqPos);
1298         if (cdr.SubqForwardSectors < SUBQ_FORWARD_SECTORS) {
1299                 cdr.SubqForwardSectors++;
1300                 CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
1301                 return;
1302         }
1303
1304         // note: CdlGetlocL should work as soon as STATUS_READ is indicated
1305         SetPlaySeekRead(cdr.StatP, STATUS_READ | STATUS_ROTATING);
1306
1307         read_ok = ReadTrack(cdr.SetSectorPlay);
1308         if (read_ok)
1309                 buf = CDR_getBuffer();
1310         if (buf == NULL)
1311                 read_ok = 0;
1312
1313         if (!read_ok) {
1314                 CDR_LOG_I("cdrReadInterrupt() Log: err\n");
1315                 cdrReadInterruptSetResult(cdr.StatP | STATUS_ERROR);
1316                 return;
1317         }
1318         memcpy(cdr.LocL, buf, 8);
1319
1320         if (!cdr.Irq1Pending)
1321                 cdrUpdateTransferBuf(buf);
1322
1323         if ((!cdr.Muted) && (cdr.Mode & MODE_STRSND) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA
1324                 hdr = buf + 4;
1325                 // Firemen 2: Multi-XA files - briefings, cutscenes
1326                 if( cdr.FirstSector == 1 && (cdr.Mode & MODE_SF)==0 ) {
1327                         cdr.File = hdr[0];
1328                         cdr.Channel = hdr[1];
1329                 }
1330
1331                 /* Gameblabla 
1332                  * Skips playing on channel 255.
1333                  * Fixes missing audio in Blue's Clues : Blue's Big Musical. (Should also fix Taxi 2)
1334                  * TODO : Check if this is the proper behaviour.
1335                  * */
1336                 if ((hdr[2] & 0x4) && hdr[0] == cdr.File && hdr[1] == cdr.Channel && cdr.Channel != 255) {
1337                         int ret = xa_decode_sector(&cdr.Xa, buf + 4, cdr.FirstSector);
1338                         if (!ret) {
1339                                 cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo);
1340                                 SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, cdr.FirstSector);
1341                                 cdr.FirstSector = 0;
1342                         }
1343                         else cdr.FirstSector = -1;
1344                 }
1345         }
1346
1347         /*
1348         Croc 2: $40 - only FORM1 (*)
1349         Judge Dredd: $C8 - only FORM1 (*)
1350         Sim Theme Park - no adpcm at all (zero)
1351         */
1352
1353         if (!(cdr.Mode & MODE_STRSND) || !(buf[4+2] & 0x4))
1354                 cdrReadInterruptSetResult(cdr.StatP);
1355
1356         msfiAdd(cdr.SetSectorPlay, 1);
1357
1358         CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
1359 }
1360
1361 /*
1362 cdrRead0:
1363         bit 0,1 - mode
1364         bit 2 - unknown
1365         bit 3 - unknown
1366         bit 4 - unknown
1367         bit 5 - 1 result ready
1368         bit 6 - 1 dma ready
1369         bit 7 - 1 command being processed
1370 */
1371
1372 unsigned char cdrRead0(void) {
1373         if (cdr.ResultReady)
1374                 cdr.Ctrl |= 0x20;
1375         else
1376                 cdr.Ctrl &= ~0x20;
1377
1378         cdr.Ctrl |= 0x40; // data fifo not empty
1379
1380         // What means the 0x10 and the 0x08 bits? I only saw it used by the bios
1381         cdr.Ctrl |= 0x18;
1382
1383         CDR_LOG_IO("cdr r0.sta: %02x\n", cdr.Ctrl);
1384
1385         return psxHu8(0x1800) = cdr.Ctrl;
1386 }
1387
1388 void cdrWrite0(unsigned char rt) {
1389         CDR_LOG_IO("cdr w0.idx: %02x\n", rt);
1390
1391         cdr.Ctrl = (rt & 3) | (cdr.Ctrl & ~3);
1392 }
1393
1394 unsigned char cdrRead1(void) {
1395         if ((cdr.ResultP & 0xf) < cdr.ResultC)
1396                 psxHu8(0x1801) = cdr.Result[cdr.ResultP & 0xf];
1397         else
1398                 psxHu8(0x1801) = 0;
1399         cdr.ResultP++;
1400         if (cdr.ResultP == cdr.ResultC)
1401                 cdr.ResultReady = 0;
1402
1403         CDR_LOG_IO("cdr r1.rsp: %02x #%u\n", psxHu8(0x1801), cdr.ResultP - 1);
1404
1405         return psxHu8(0x1801);
1406 }
1407
1408 void cdrWrite1(unsigned char rt) {
1409         const char *rnames[] = { "cmd", "smd", "smc", "arr" }; (void)rnames;
1410         CDR_LOG_IO("cdr w1.%s: %02x\n", rnames[cdr.Ctrl & 3], rt);
1411
1412         switch (cdr.Ctrl & 3) {
1413         case 0:
1414                 break;
1415         case 3:
1416                 cdr.AttenuatorRightToRightT = rt;
1417                 return;
1418         default:
1419                 return;
1420         }
1421
1422 #ifdef CDR_LOG_CMD_IRQ
1423         SysPrintf("%u cdrom: CD1 write: %x (%s)", psxRegs.cycle, rt, CmdName[rt]);
1424         if (cdr.ParamC) {
1425                 int i;
1426                 SysPrintf(" Param[%d] = {", cdr.ParamC);
1427                 for (i = 0; i < cdr.ParamC; i++)
1428                         SysPrintf(" %x,", cdr.Param[i]);
1429                 SysPrintf("}\n");
1430         } else {
1431                 SysPrintf("\n");
1432         }
1433 #endif
1434
1435         cdr.ResultReady = 0;
1436         cdr.Ctrl |= 0x80;
1437
1438         if (!cdr.CmdInProgress) {
1439                 cdr.CmdInProgress = rt;
1440                 // should be something like 12k + controller delays
1441                 CDR_INT(5000);
1442         }
1443         else {
1444                 CDR_LOG_I("%u cdrom: cmd while busy: %02x, prev %02x, busy %02x\n",
1445                         psxRegs.cycle, rt, cdr.Cmd, cdr.CmdInProgress);
1446                 if (cdr.CmdInProgress < 0x100) // no pending 2nd response
1447                         cdr.CmdInProgress = rt;
1448         }
1449
1450         cdr.Cmd = rt;
1451 }
1452
1453 unsigned char cdrRead2(void) {
1454         unsigned char ret = cdr.Transfer[0x920];
1455
1456         if (cdr.FifoOffset < cdr.FifoSize)
1457                 ret = cdr.Transfer[cdr.FifoOffset++];
1458         else
1459                 CDR_LOG_I("cdrom: read empty fifo (%d)\n", cdr.FifoSize);
1460
1461         CDR_LOG_IO("cdr r2.dat: %02x\n", ret);
1462         return ret;
1463 }
1464
1465 void cdrWrite2(unsigned char rt) {
1466         const char *rnames[] = { "prm", "ien", "all", "arl" }; (void)rnames;
1467         CDR_LOG_IO("cdr w2.%s: %02x\n", rnames[cdr.Ctrl & 3], rt);
1468
1469         switch (cdr.Ctrl & 3) {
1470         case 0:
1471                 if (cdr.ParamC < 8) // FIXME: size and wrapping
1472                         cdr.Param[cdr.ParamC++] = rt;
1473                 return;
1474         case 1:
1475                 cdr.Reg2 = rt;
1476                 setIrq(0x1005);
1477                 return;
1478         case 2:
1479                 cdr.AttenuatorLeftToLeftT = rt;
1480                 return;
1481         case 3:
1482                 cdr.AttenuatorRightToLeftT = rt;
1483                 return;
1484         }
1485 }
1486
1487 unsigned char cdrRead3(void) {
1488         if (cdr.Ctrl & 0x1)
1489                 psxHu8(0x1803) = cdr.Stat | 0xE0;
1490         else
1491                 psxHu8(0x1803) = cdr.Reg2 | 0xE0;
1492
1493         CDR_LOG_IO("cdr r3.%s: %02x\n", (cdr.Ctrl & 1) ? "ifl" : "ien", psxHu8(0x1803));
1494         return psxHu8(0x1803);
1495 }
1496
1497 void cdrWrite3(unsigned char rt) {
1498         const char *rnames[] = { "req", "ifl", "alr", "ava" }; (void)rnames;
1499         CDR_LOG_IO("cdr w3.%s: %02x\n", rnames[cdr.Ctrl & 3], rt);
1500
1501         switch (cdr.Ctrl & 3) {
1502         case 0:
1503                 break; // transfer
1504         case 1:
1505                 if (cdr.Stat & rt) {
1506 #ifdef CDR_LOG_CMD_IRQ
1507                         SysPrintf("%u cdrom: ack %02x (w %02x)\n",
1508                                 psxRegs.cycle, cdr.Stat & rt, rt);
1509 #endif
1510                         // note: Croc vs Discworld Noir
1511                         if (!(psxRegs.interrupt & (1 << PSXINT_CDR)) &&
1512                             (cdr.CmdInProgress || cdr.Irq1Pending))
1513                                 CDR_INT(850); // 711-993
1514                 }
1515                 cdr.Stat &= ~rt;
1516
1517                 if (rt & 0x40)
1518                         cdr.ParamC = 0;
1519                 return;
1520         case 2:
1521                 cdr.AttenuatorLeftToRightT = rt;
1522                 return;
1523         case 3:
1524                 if (rt & 0x20) {
1525                         memcpy(&cdr.AttenuatorLeftToLeft, &cdr.AttenuatorLeftToLeftT, 4);
1526                         CDR_LOG("CD-XA Volume: %02x %02x | %02x %02x\n",
1527                                 cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight,
1528                                 cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight);
1529                 }
1530                 return;
1531         }
1532
1533         // test: Viewpoint
1534         if ((rt & 0x80) && cdr.FifoOffset < cdr.FifoSize) {
1535                 CDR_LOG("cdrom: FifoOffset(2) %d/%d\n", cdr.FifoOffset, cdr.FifoSize);
1536         }
1537         else if (rt & 0x80) {
1538                 switch (cdr.Mode & 0x30) {
1539                         case MODE_SIZE_2328:
1540                         case 0x00:
1541                                 cdr.FifoOffset = 12;
1542                                 cdr.FifoSize = 2048 + 12;
1543                                 break;
1544
1545                         case MODE_SIZE_2340:
1546                         default:
1547                                 cdr.FifoOffset = 0;
1548                                 cdr.FifoSize = 2340;
1549                                 break;
1550                 }
1551         }
1552         else if (!(rt & 0xc0))
1553                 cdr.FifoOffset = DATA_SIZE; // fifo empty
1554 }
1555
1556 void psxDma3(u32 madr, u32 bcr, u32 chcr) {
1557         u32 cdsize;
1558         int size;
1559         u8 *ptr;
1560
1561         CDR_LOG("psxDma3() Log: *** DMA 3 *** %x addr = %x size = %x\n", chcr, madr, bcr);
1562
1563         switch (chcr & 0x71000000) {
1564                 case 0x11000000:
1565                         ptr = (u8 *)PSXM(madr);
1566                         if (ptr == INVALID_PTR) {
1567                                 CDR_LOG_I("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n");
1568                                 break;
1569                         }
1570
1571                         cdsize = (((bcr - 1) & 0xffff) + 1) * 4;
1572
1573                         /*
1574                         GS CDX: Enhancement CD crash
1575                         - Setloc 0:0:0
1576                         - CdlPlay
1577                         - Spams DMA3 and gets buffer overrun
1578                         */
1579                         size = DATA_SIZE - cdr.FifoOffset;
1580                         if (size > cdsize)
1581                                 size = cdsize;
1582                         if (size > 0)
1583                         {
1584                                 memcpy(ptr, cdr.Transfer + cdr.FifoOffset, size);
1585                                 cdr.FifoOffset += size;
1586                         }
1587                         if (size < cdsize) {
1588                                 CDR_LOG_I("cdrom: dma3 %d/%d\n", size, cdsize);
1589                                 memset(ptr + size, cdr.Transfer[0x920], cdsize - size);
1590                         }
1591                         psxCpu->Clear(madr, cdsize / 4);
1592
1593                         CDRDMA_INT((cdsize/4) * 24);
1594
1595                         HW_DMA3_CHCR &= SWAPu32(~0x10000000);
1596                         if (chcr & 0x100) {
1597                                 HW_DMA3_MADR = SWAPu32(madr + cdsize);
1598                                 HW_DMA3_BCR &= SWAPu32(0xffff0000);
1599                         }
1600                         else {
1601                                 // halted
1602                                 psxRegs.cycle += (cdsize/4) * 24 - 20;
1603                         }
1604                         return;
1605
1606                 default:
1607                         CDR_LOG_I("psxDma3() Log: Unknown cddma %x\n", chcr);
1608                         break;
1609         }
1610
1611         HW_DMA3_CHCR &= SWAP32(~0x01000000);
1612         DMA_INTERRUPT(3);
1613 }
1614
1615 void cdrDmaInterrupt(void)
1616 {
1617         if (HW_DMA3_CHCR & SWAP32(0x01000000))
1618         {
1619                 HW_DMA3_CHCR &= SWAP32(~0x01000000);
1620                 DMA_INTERRUPT(3);
1621         }
1622 }
1623
1624 static void getCdInfo(void)
1625 {
1626         u8 tmp;
1627
1628         CDR_getTN(cdr.ResultTN);
1629         CDR_getTD(0, cdr.SetSectorEnd);
1630         tmp = cdr.SetSectorEnd[0];
1631         cdr.SetSectorEnd[0] = cdr.SetSectorEnd[2];
1632         cdr.SetSectorEnd[2] = tmp;
1633 }
1634
1635 void cdrReset() {
1636         memset(&cdr, 0, sizeof(cdr));
1637         cdr.CurTrack = 1;
1638         cdr.File = 1;
1639         cdr.Channel = 1;
1640         cdr.Reg2 = 0x1f;
1641         cdr.Stat = NoIntr;
1642         cdr.FifoOffset = DATA_SIZE; // fifo empty
1643         if (CdromId[0] == '\0') {
1644                 cdr.DriveState = DRIVESTATE_STOPPED;
1645                 cdr.StatP = 0;
1646         }
1647         else {
1648                 cdr.DriveState = DRIVESTATE_STANDBY;
1649                 cdr.StatP = STATUS_ROTATING;
1650         }
1651         
1652         // BIOS player - default values
1653         cdr.AttenuatorLeftToLeft = 0x80;
1654         cdr.AttenuatorLeftToRight = 0x00;
1655         cdr.AttenuatorRightToLeft = 0x00;
1656         cdr.AttenuatorRightToRight = 0x80;
1657
1658         getCdInfo();
1659 }
1660
1661 int cdrFreeze(void *f, int Mode) {
1662         u32 tmp;
1663         u8 tmpp[3];
1664
1665         if (Mode == 0 && !Config.Cdda)
1666                 CDR_stop();
1667         
1668         cdr.freeze_ver = 0x63647202;
1669         gzfreeze(&cdr, sizeof(cdr));
1670         
1671         if (Mode == 1) {
1672                 cdr.ParamP = cdr.ParamC;
1673                 tmp = cdr.FifoOffset;
1674         }
1675
1676         gzfreeze(&tmp, sizeof(tmp));
1677
1678         if (Mode == 0) {
1679                 getCdInfo();
1680
1681                 cdr.FifoOffset = tmp < DATA_SIZE ? tmp : DATA_SIZE;
1682                 cdr.FifoSize = (cdr.Mode & 0x20) ? 2340 : 2048 + 12;
1683                 if (cdr.SubqForwardSectors > SUBQ_FORWARD_SECTORS)
1684                         cdr.SubqForwardSectors = SUBQ_FORWARD_SECTORS;
1685
1686                 // read right sub data
1687                 tmpp[0] = btoi(cdr.Prev[0]);
1688                 tmpp[1] = btoi(cdr.Prev[1]);
1689                 tmpp[2] = btoi(cdr.Prev[2]);
1690                 cdr.Prev[0]++;
1691                 ReadTrack(tmpp);
1692
1693                 if (cdr.Play) {
1694                         if (cdr.freeze_ver < 0x63647202)
1695                                 memcpy(cdr.SetSectorPlay, cdr.SetSector, 3);
1696
1697                         Find_CurTrack(cdr.SetSectorPlay);
1698                         if (!Config.Cdda)
1699                                 CDR_play(cdr.SetSectorPlay);
1700                         if (psxRegs.interrupt & (1 << PSXINT_CDRPLAY_OLD))
1701                                 CDRPLAYREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime, 1);
1702                 }
1703
1704                 if ((cdr.freeze_ver & 0xffffff00) != 0x63647200) {
1705                         // old versions did not latch Reg2, have to fixup..
1706                         if (cdr.Reg2 == 0) {
1707                                 SysPrintf("cdrom: fixing up old savestate\n");
1708                                 cdr.Reg2 = 7;
1709                         }
1710                         // also did not save Attenuator..
1711                         if ((cdr.AttenuatorLeftToLeft | cdr.AttenuatorLeftToRight
1712                              | cdr.AttenuatorRightToLeft | cdr.AttenuatorRightToRight) == 0)
1713                         {
1714                                 cdr.AttenuatorLeftToLeft = cdr.AttenuatorRightToRight = 0x80;
1715                         }
1716                 }
1717         }
1718
1719         return 0;
1720 }
1721
1722 void LidInterrupt(void) {
1723         getCdInfo();
1724         cdrLidSeekInterrupt();
1725 }