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