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