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