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