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