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