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