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