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