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