cdrom: allow resetting with lid open
[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
1136                         /* This adds the string "PCSX" in Playstation bios boot screen */
1137                         memcpy((char *)&cdr.Result[4], "PCSX", 4);
1138                         cdr.Stat = Complete;
1139                         break;
1140
1141                 case CdlInit:
1142                 case CdlInit + CMD_WHILE_NOT_READY:
1143                         StopCdda();
1144                         StopReading();
1145                         SetPlaySeekRead(cdr.StatP, 0);
1146                         // yes, it really sets STATUS_SHELLOPEN
1147                         cdr.StatP |= STATUS_SHELLOPEN;
1148                         cdr.DriveState = DRIVESTATE_RESCAN_CD;
1149                         set_event(PSXINT_CDRLID, 20480);
1150                         start_rotating = 1;
1151                         break;
1152
1153                 case CdlGetQ:
1154                 case CdlGetQ + CMD_WHILE_NOT_READY:
1155                         break;
1156
1157                 case CdlReadToc:
1158                 case CdlReadToc + CMD_WHILE_NOT_READY:
1159                         cdr.LocL[0] = LOCL_INVALID;
1160                         second_resp_time = cdReadTime * 180 / 4;
1161                         start_rotating = 1;
1162                         break;
1163
1164                 case CdlReadToc + CMD_PART2:
1165                 case CdlReadToc + CMD_PART2 + CMD_WHILE_NOT_READY:
1166                         cdr.Stat = Complete;
1167                         break;
1168
1169                 case CdlReadN:
1170                 case CdlReadS:
1171                         if (cdr.Reading && !cdr.SetlocPending)
1172                                 break;
1173
1174                         Find_CurTrack(cdr.SetlocPending ? cdr.SetSector : cdr.SetSectorPlay);
1175
1176                         if ((cdr.Mode & MODE_CDDA) && cdr.CurTrack > 1)
1177                                 // Read* acts as play for cdda tracks in cdda mode
1178                                 goto do_CdlPlay;
1179
1180                         StopCdda();
1181                         if (cdr.SetlocPending) {
1182                                 seekTime = cdrSeekTime(cdr.SetSector);
1183                                 memcpy(cdr.SetSectorPlay, cdr.SetSector, 4);
1184                                 cdr.SetlocPending = 0;
1185                         }
1186                         cdr.Reading = 1;
1187                         cdr.FirstSector = 1;
1188
1189                         // Fighting Force 2 - update subq time immediately
1190                         // - fixes new game
1191                         UpdateSubq(cdr.SetSectorPlay);
1192                         cdr.LocL[0] = LOCL_INVALID;
1193                         cdr.SubqForwardSectors = 1;
1194                         cdr.sectorsRead = 0;
1195
1196                         cycles = (cdr.Mode & MODE_SPEED) ? cdReadTime : cdReadTime * 2;
1197                         cycles += seekTime;
1198                         if (Config.hacks.cdr_read_timing)
1199                                 cycles = cdrAlignTimingHack(cycles);
1200                         CDRPLAYREAD_INT(cycles, 1);
1201
1202                         SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
1203                         start_rotating = 1;
1204                         break;
1205
1206                 case CdlSync:
1207                 default:
1208                         error = ERROR_INVALIDCMD;
1209                         // FALLTHROUGH
1210
1211                 set_error:
1212                         SetResultSize(2);
1213                         cdr.Result[0] = cdr.StatP | STATUS_ERROR;
1214                         cdr.Result[1] = not_ready ? ERROR_NOTREADY : error;
1215                         cdr.Stat = DiskError;
1216                         CDR_LOG_I("cmd %02x error %02x\n", Cmd, cdr.Result[1]);
1217                         break;
1218         }
1219
1220         if (cdr.DriveState == DRIVESTATE_STOPPED && start_rotating) {
1221                 cdr.DriveState = DRIVESTATE_STANDBY;
1222                 cdr.StatP |= STATUS_ROTATING;
1223         }
1224
1225         if (second_resp_time) {
1226                 cdr.CmdInProgress = Cmd | 0x100;
1227                 set_event(PSXINT_CDR, second_resp_time);
1228         }
1229         else if (cdr.Cmd && cdr.Cmd != (Cmd & 0xff)) {
1230                 cdr.CmdInProgress = cdr.Cmd;
1231                 CDR_LOG_I("cmd %02x came before %02x finished\n", cdr.Cmd, Cmd);
1232         }
1233
1234         setIrq(Cmd);
1235 }
1236
1237 #ifdef HAVE_ARMV7
1238  #define ssat32_to_16(v) \
1239   asm("ssat %0,#16,%1" : "=r" (v) : "r" (v))
1240 #else
1241  #define ssat32_to_16(v) do { \
1242   if (v < -32768) v = -32768; \
1243   else if (v > 32767) v = 32767; \
1244  } while (0)
1245 #endif
1246
1247 static void cdrPrepCdda(s16 *buf, int samples)
1248 {
1249 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1250         int i;
1251         for (i = 0; i < samples; i++) {
1252                 buf[i * 2 + 0] = SWAP16(buf[i * 2 + 0]);
1253                 buf[i * 2 + 1] = SWAP16(buf[i * 2 + 1]);
1254         }
1255 #endif
1256 }
1257
1258 static void cdrAttenuate(s16 *buf, int samples, int stereo)
1259 {
1260         int i, l, r;
1261         int ll = cdr.AttenuatorLeftToLeft;
1262         int lr = cdr.AttenuatorLeftToRight;
1263         int rl = cdr.AttenuatorRightToLeft;
1264         int rr = cdr.AttenuatorRightToRight;
1265
1266         if (lr == 0 && rl == 0 && 0x78 <= ll && ll <= 0x88 && 0x78 <= rr && rr <= 0x88)
1267                 return;
1268
1269         if (!stereo && ll == 0x40 && lr == 0x40 && rl == 0x40 && rr == 0x40)
1270                 return;
1271
1272         if (stereo) {
1273                 for (i = 0; i < samples; i++) {
1274                         l = buf[i * 2];
1275                         r = buf[i * 2 + 1];
1276                         l = (l * ll + r * rl) >> 7;
1277                         r = (r * rr + l * lr) >> 7;
1278                         ssat32_to_16(l);
1279                         ssat32_to_16(r);
1280                         buf[i * 2] = l;
1281                         buf[i * 2 + 1] = r;
1282                 }
1283         }
1284         else {
1285                 for (i = 0; i < samples; i++) {
1286                         l = buf[i];
1287                         l = l * (ll + rl) >> 7;
1288                         //r = r * (rr + lr) >> 7;
1289                         ssat32_to_16(l);
1290                         //ssat32_to_16(r);
1291                         buf[i] = l;
1292                 }
1293         }
1294 }
1295
1296 static void cdrReadInterruptSetResult(unsigned char result)
1297 {
1298         if (cdr.Stat) {
1299                 CDR_LOG_I("%d:%02d:%02d irq miss, cmd=%02x irqstat=%02x\n",
1300                         cdr.SetSectorPlay[0], cdr.SetSectorPlay[1], cdr.SetSectorPlay[2],
1301                         cdr.CmdInProgress, cdr.Stat);
1302                 cdr.Irq1Pending = result;
1303                 return;
1304         }
1305         SetResultSize(1);
1306         cdr.Result[0] = result;
1307         cdr.Stat = (result & STATUS_ERROR) ? DiskError : DataReady;
1308         setIrq(0x1004);
1309 }
1310
1311 static void cdrUpdateTransferBuf(const u8 *buf)
1312 {
1313         if (!buf)
1314                 return;
1315         memcpy(cdr.Transfer, buf, DATA_SIZE);
1316         CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
1317         CDR_LOG("cdr.Transfer  %02x:%02x:%02x\n",
1318                 cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
1319         if (cdr.FifoOffset < 2048 + 12)
1320                 CDR_LOG("FifoOffset(1) %d/%d\n", cdr.FifoOffset, cdr.FifoSize);
1321 }
1322
1323 static void cdrReadInterrupt(void)
1324 {
1325         u8 *buf = NULL, *hdr;
1326         u8 subqPos[3];
1327         int read_ok;
1328
1329         memcpy(subqPos, cdr.SetSectorPlay, sizeof(subqPos));
1330         msfiAdd(subqPos, cdr.SubqForwardSectors);
1331         UpdateSubq(subqPos);
1332         if (cdr.SubqForwardSectors < SUBQ_FORWARD_SECTORS) {
1333                 cdr.SubqForwardSectors++;
1334                 CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
1335                 return;
1336         }
1337
1338         // note: CdlGetlocL should work as soon as STATUS_READ is indicated
1339         SetPlaySeekRead(cdr.StatP, STATUS_READ | STATUS_ROTATING);
1340         cdr.sectorsRead++;
1341
1342         read_ok = ReadTrack(cdr.SetSectorPlay);
1343         if (read_ok)
1344                 buf = CDR_getBuffer();
1345         if (buf == NULL)
1346                 read_ok = 0;
1347
1348         if (!read_ok) {
1349                 CDR_LOG_I("cdrReadInterrupt() Log: err\n");
1350                 cdrReadInterruptSetResult(cdr.StatP | STATUS_ERROR);
1351                 return;
1352         }
1353         memcpy(cdr.LocL, buf, 8);
1354
1355         if (!cdr.Stat && !cdr.Irq1Pending)
1356                 cdrUpdateTransferBuf(buf);
1357
1358         if ((!cdr.Muted) && (cdr.Mode & MODE_STRSND) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA
1359                 hdr = buf + 4;
1360                 // Firemen 2: Multi-XA files - briefings, cutscenes
1361                 if( cdr.FirstSector == 1 && (cdr.Mode & MODE_SF)==0 ) {
1362                         cdr.File = hdr[0];
1363                         cdr.Channel = hdr[1];
1364                 }
1365
1366                 /* Gameblabla 
1367                  * Skips playing on channel 255.
1368                  * Fixes missing audio in Blue's Clues : Blue's Big Musical. (Should also fix Taxi 2)
1369                  * TODO : Check if this is the proper behaviour.
1370                  * */
1371                 if ((hdr[2] & 0x4) && hdr[0] == cdr.File && hdr[1] == cdr.Channel && cdr.Channel != 255) {
1372                         int ret = xa_decode_sector(&cdr.Xa, buf + 4, cdr.FirstSector);
1373                         if (!ret) {
1374                                 cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo);
1375                                 SPU_playADPCMchannel(&cdr.Xa, psxRegs.cycle, cdr.FirstSector);
1376                                 cdr.FirstSector = 0;
1377                         }
1378                         else cdr.FirstSector = -1;
1379                 }
1380         }
1381
1382         /*
1383         Croc 2: $40 - only FORM1 (*)
1384         Judge Dredd: $C8 - only FORM1 (*)
1385         Sim Theme Park - no adpcm at all (zero)
1386         */
1387
1388         if (!(cdr.Mode & MODE_STRSND) || !(buf[4+2] & 0x4))
1389                 cdrReadInterruptSetResult(cdr.StatP);
1390
1391         msfiAdd(cdr.SetSectorPlay, 1);
1392
1393         CDRPLAYREAD_INT((cdr.Mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime, 0);
1394 }
1395
1396 /*
1397 cdrRead0:
1398         bit 0,1 - mode
1399         bit 2 - unknown
1400         bit 3 - unknown
1401         bit 4 - unknown
1402         bit 5 - 1 result ready
1403         bit 6 - 1 dma ready
1404         bit 7 - 1 command being processed
1405 */
1406
1407 unsigned char cdrRead0(void) {
1408         if (cdr.ResultReady)
1409                 cdr.Ctrl |= 0x20;
1410         else
1411                 cdr.Ctrl &= ~0x20;
1412
1413         cdr.Ctrl |= 0x40; // data fifo not empty
1414
1415         // What means the 0x10 and the 0x08 bits? I only saw it used by the bios
1416         cdr.Ctrl |= 0x18;
1417
1418         CDR_LOG_IO("cdr r0.sta: %02x\n", cdr.Ctrl);
1419
1420         return psxHu8(0x1800) = cdr.Ctrl;
1421 }
1422
1423 void cdrWrite0(unsigned char rt) {
1424         CDR_LOG_IO("cdr w0.idx: %02x\n", rt);
1425
1426         cdr.Ctrl = (rt & 3) | (cdr.Ctrl & ~3);
1427 }
1428
1429 unsigned char cdrRead1(void) {
1430         if ((cdr.ResultP & 0xf) < cdr.ResultC)
1431                 psxHu8(0x1801) = cdr.Result[cdr.ResultP & 0xf];
1432         else
1433                 psxHu8(0x1801) = 0;
1434         cdr.ResultP++;
1435         if (cdr.ResultP == cdr.ResultC)
1436                 cdr.ResultReady = 0;
1437
1438         CDR_LOG_IO("cdr r1.rsp: %02x #%u\n", psxHu8(0x1801), cdr.ResultP - 1);
1439
1440         return psxHu8(0x1801);
1441 }
1442
1443 void cdrWrite1(unsigned char rt) {
1444         const char *rnames[] = { "cmd", "smd", "smc", "arr" }; (void)rnames;
1445         CDR_LOG_IO("cdr w1.%s: %02x\n", rnames[cdr.Ctrl & 3], rt);
1446
1447         switch (cdr.Ctrl & 3) {
1448         case 0:
1449                 break;
1450         case 3:
1451                 cdr.AttenuatorRightToRightT = rt;
1452                 return;
1453         default:
1454                 return;
1455         }
1456
1457 #ifdef CDR_LOG_CMD_IRQ
1458         CDR_LOG_I("CD1 write: %x (%s)", rt, CmdName[rt]);
1459         if (cdr.ParamC) {
1460                 int i;
1461                 SysPrintf(" Param[%d] = {", cdr.ParamC);
1462                 for (i = 0; i < cdr.ParamC; i++)
1463                         SysPrintf(" %x,", cdr.Param[i]);
1464                 SysPrintf("}\n");
1465         } else {
1466                 SysPrintf("\n");
1467         }
1468 #endif
1469
1470         cdr.ResultReady = 0;
1471         cdr.Ctrl |= 0x80;
1472
1473         if (!cdr.CmdInProgress) {
1474                 cdr.CmdInProgress = rt;
1475                 // should be something like 12k + controller delays
1476                 set_event(PSXINT_CDR, 5000);
1477         }
1478         else {
1479                 CDR_LOG_I("cmd while busy: %02x, prev %02x, busy %02x\n",
1480                         rt, cdr.Cmd, cdr.CmdInProgress);
1481                 if (cdr.CmdInProgress < 0x100) // no pending 2nd response
1482                         cdr.CmdInProgress = rt;
1483         }
1484
1485         cdr.Cmd = rt;
1486 }
1487
1488 unsigned char cdrRead2(void) {
1489         unsigned char ret = cdr.Transfer[0x920];
1490
1491         if (cdr.FifoOffset < cdr.FifoSize)
1492                 ret = cdr.Transfer[cdr.FifoOffset++];
1493         else
1494                 CDR_LOG_I("read empty fifo (%d)\n", cdr.FifoSize);
1495
1496         CDR_LOG_IO("cdr r2.dat: %02x\n", ret);
1497         return ret;
1498 }
1499
1500 void cdrWrite2(unsigned char rt) {
1501         const char *rnames[] = { "prm", "ien", "all", "arl" }; (void)rnames;
1502         CDR_LOG_IO("cdr w2.%s: %02x\n", rnames[cdr.Ctrl & 3], rt);
1503
1504         switch (cdr.Ctrl & 3) {
1505         case 0:
1506                 if (cdr.ParamC < 8) // FIXME: size and wrapping
1507                         cdr.Param[cdr.ParamC++] = rt;
1508                 return;
1509         case 1:
1510                 cdr.Reg2 = rt;
1511                 setIrq(0x1005);
1512                 return;
1513         case 2:
1514                 cdr.AttenuatorLeftToLeftT = rt;
1515                 return;
1516         case 3:
1517                 cdr.AttenuatorRightToLeftT = rt;
1518                 return;
1519         }
1520 }
1521
1522 unsigned char cdrRead3(void) {
1523         if (cdr.Ctrl & 0x1)
1524                 psxHu8(0x1803) = cdr.Stat | 0xE0;
1525         else
1526                 psxHu8(0x1803) = cdr.Reg2 | 0xE0;
1527
1528         CDR_LOG_IO("cdr r3.%s: %02x\n", (cdr.Ctrl & 1) ? "ifl" : "ien", psxHu8(0x1803));
1529         return psxHu8(0x1803);
1530 }
1531
1532 void cdrWrite3(unsigned char rt) {
1533         const char *rnames[] = { "req", "ifl", "alr", "ava" }; (void)rnames;
1534         CDR_LOG_IO("cdr w3.%s: %02x\n", rnames[cdr.Ctrl & 3], rt);
1535
1536         switch (cdr.Ctrl & 3) {
1537         case 0:
1538                 break; // transfer
1539         case 1:
1540                 if (cdr.Stat & rt) {
1541                         u32 nextCycle = psxRegs.intCycle[PSXINT_CDR].sCycle
1542                                 + psxRegs.intCycle[PSXINT_CDR].cycle;
1543                         int pending = psxRegs.interrupt & (1 << PSXINT_CDR);
1544 #ifdef CDR_LOG_CMD_IRQ
1545                         CDR_LOG_I("ack %02x (w=%02x p=%d,%x,%x,%d)\n", cdr.Stat & rt, rt,
1546                                 !!pending, cdr.CmdInProgress,
1547                                 cdr.Irq1Pending, nextCycle - psxRegs.cycle);
1548 #endif
1549                         // note: Croc, Shadow Tower (more) vs Discworld Noir (<993)
1550                         if (!pending && (cdr.CmdInProgress || cdr.Irq1Pending))
1551                         {
1552                                 s32 c = 2048;
1553                                 if (cdr.CmdInProgress) {
1554                                         c = 2048 - (psxRegs.cycle - nextCycle);
1555                                         c = MAX_VALUE(c, 512);
1556                                 }
1557                                 set_event(PSXINT_CDR, c);
1558                         }
1559                 }
1560                 cdr.Stat &= ~rt;
1561
1562                 if (rt & 0x40)
1563                         cdr.ParamC = 0;
1564                 return;
1565         case 2:
1566                 cdr.AttenuatorLeftToRightT = rt;
1567                 return;
1568         case 3:
1569                 if (rt & 0x20) {
1570                         memcpy(&cdr.AttenuatorLeftToLeft, &cdr.AttenuatorLeftToLeftT, 4);
1571                         CDR_LOG("CD-XA Volume: %02x %02x | %02x %02x\n",
1572                                 cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight,
1573                                 cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight);
1574                 }
1575                 return;
1576         }
1577
1578         // test: Viewpoint
1579         if ((rt & 0x80) && cdr.FifoOffset < cdr.FifoSize) {
1580                 CDR_LOG("cdrom: FifoOffset(2) %d/%d\n", cdr.FifoOffset, cdr.FifoSize);
1581         }
1582         else if (rt & 0x80) {
1583                 switch (cdr.Mode & (MODE_SIZE_2328|MODE_SIZE_2340)) {
1584                         case MODE_SIZE_2328:
1585                         case 0x00:
1586                                 cdr.FifoOffset = 12;
1587                                 cdr.FifoSize = 2048 + 12;
1588                                 break;
1589
1590                         case MODE_SIZE_2340:
1591                         default:
1592                                 cdr.FifoOffset = 0;
1593                                 cdr.FifoSize = 2340;
1594                                 break;
1595                 }
1596         }
1597         else if (!(rt & 0xc0))
1598                 cdr.FifoOffset = DATA_SIZE; // fifo empty
1599 }
1600
1601 void psxDma3(u32 madr, u32 bcr, u32 chcr) {
1602         u32 cdsize, max_words;
1603         int size;
1604         u8 *ptr;
1605
1606 #if 0
1607         CDR_LOG_I("psxDma3() Log: *** DMA 3 *** %x addr = %x size = %x", chcr, madr, bcr);
1608         if (cdr.FifoOffset == 0) {
1609                 ptr = cdr.Transfer;
1610                 SysPrintf(" %02x:%02x:%02x", ptr[0], ptr[1], ptr[2]);
1611         }
1612         SysPrintf("\n");
1613 #endif
1614
1615         switch (chcr & 0x71000000) {
1616                 case 0x11000000:
1617                         ptr = getDmaRam(madr, &max_words);
1618                         if (ptr == INVALID_PTR) {
1619                                 CDR_LOG_I("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n");
1620                                 break;
1621                         }
1622
1623                         cdsize = (((bcr - 1) & 0xffff) + 1) * 4;
1624
1625                         /*
1626                         GS CDX: Enhancement CD crash
1627                         - Setloc 0:0:0
1628                         - CdlPlay
1629                         - Spams DMA3 and gets buffer overrun
1630                         */
1631                         size = DATA_SIZE - cdr.FifoOffset;
1632                         if (size > cdsize)
1633                                 size = cdsize;
1634                         if (size > max_words * 4)
1635                                 size = max_words * 4;
1636                         if (size > 0)
1637                         {
1638                                 memcpy(ptr, cdr.Transfer + cdr.FifoOffset, size);
1639                                 cdr.FifoOffset += size;
1640                         }
1641                         if (size < cdsize) {
1642                                 CDR_LOG_I("cdrom: dma3 %d/%d\n", size, cdsize);
1643                                 memset(ptr + size, cdr.Transfer[0x920], cdsize - size);
1644                         }
1645                         psxCpu->Clear(madr, cdsize / 4);
1646
1647                         set_event(PSXINT_CDRDMA, (cdsize / 4) * 24);
1648
1649                         HW_DMA3_CHCR &= SWAPu32(~0x10000000);
1650                         if (chcr & 0x100) {
1651                                 HW_DMA3_MADR = SWAPu32(madr + cdsize);
1652                                 HW_DMA3_BCR &= SWAPu32(0xffff0000);
1653                         }
1654                         else {
1655                                 // halted
1656                                 psxRegs.cycle += (cdsize/4) * 24 - 20;
1657                         }
1658                         return;
1659
1660                 default:
1661                         CDR_LOG_I("psxDma3() Log: Unknown cddma %x\n", chcr);
1662                         break;
1663         }
1664
1665         HW_DMA3_CHCR &= SWAP32(~0x01000000);
1666         DMA_INTERRUPT(3);
1667 }
1668
1669 void cdrDmaInterrupt(void)
1670 {
1671         if (HW_DMA3_CHCR & SWAP32(0x01000000))
1672         {
1673                 HW_DMA3_CHCR &= SWAP32(~0x01000000);
1674                 DMA_INTERRUPT(3);
1675         }
1676 }
1677
1678 static void getCdInfo(void)
1679 {
1680         u8 tmp;
1681
1682         CDR_getTN(cdr.ResultTN);
1683         CDR_getTD(0, cdr.SetSectorEnd);
1684         tmp = cdr.SetSectorEnd[0];
1685         cdr.SetSectorEnd[0] = cdr.SetSectorEnd[2];
1686         cdr.SetSectorEnd[2] = tmp;
1687 }
1688
1689 void cdrReset() {
1690         memset(&cdr, 0, sizeof(cdr));
1691         cdr.CurTrack = 1;
1692         cdr.File = 1;
1693         cdr.Channel = 1;
1694         cdr.Reg2 = 0x1f;
1695         cdr.Stat = NoIntr;
1696         cdr.FifoOffset = DATA_SIZE; // fifo empty
1697
1698         CDR_getStatus(&stat);
1699         if (stat.Status & STATUS_SHELLOPEN) {
1700                 cdr.DriveState = DRIVESTATE_LID_OPEN;
1701                 cdr.StatP = STATUS_SHELLOPEN;
1702         }
1703         else if (CdromId[0] == '\0') {
1704                 cdr.DriveState = DRIVESTATE_STOPPED;
1705                 cdr.StatP = 0;
1706         }
1707         else {
1708                 cdr.DriveState = DRIVESTATE_STANDBY;
1709                 cdr.StatP = STATUS_ROTATING;
1710         }
1711         
1712         // BIOS player - default values
1713         cdr.AttenuatorLeftToLeft = 0x80;
1714         cdr.AttenuatorLeftToRight = 0x00;
1715         cdr.AttenuatorRightToLeft = 0x00;
1716         cdr.AttenuatorRightToRight = 0x80;
1717
1718         getCdInfo();
1719 }
1720
1721 int cdrFreeze(void *f, int Mode) {
1722         u32 tmp;
1723         u8 tmpp[3];
1724
1725         if (Mode == 0 && !Config.Cdda)
1726                 CDR_stop();
1727         
1728         cdr.freeze_ver = 0x63647202;
1729         gzfreeze(&cdr, sizeof(cdr));
1730         
1731         if (Mode == 1) {
1732                 cdr.ParamP = cdr.ParamC;
1733                 tmp = cdr.FifoOffset;
1734         }
1735
1736         gzfreeze(&tmp, sizeof(tmp));
1737
1738         if (Mode == 0) {
1739                 getCdInfo();
1740
1741                 cdr.FifoOffset = tmp < DATA_SIZE ? tmp : DATA_SIZE;
1742                 cdr.FifoSize = (cdr.Mode & MODE_SIZE_2340) ? 2340 : 2048 + 12;
1743                 if (cdr.SubqForwardSectors > SUBQ_FORWARD_SECTORS)
1744                         cdr.SubqForwardSectors = SUBQ_FORWARD_SECTORS;
1745
1746                 // read right sub data
1747                 tmpp[0] = btoi(cdr.Prev[0]);
1748                 tmpp[1] = btoi(cdr.Prev[1]);
1749                 tmpp[2] = btoi(cdr.Prev[2]);
1750                 cdr.Prev[0]++;
1751                 ReadTrack(tmpp);
1752
1753                 if (cdr.Play) {
1754                         if (cdr.freeze_ver < 0x63647202)
1755                                 memcpy(cdr.SetSectorPlay, cdr.SetSector, 3);
1756
1757                         Find_CurTrack(cdr.SetSectorPlay);
1758                         if (!Config.Cdda)
1759                                 CDR_play(cdr.SetSectorPlay);
1760                 }
1761
1762                 if ((cdr.freeze_ver & 0xffffff00) != 0x63647200) {
1763                         // old versions did not latch Reg2, have to fixup..
1764                         if (cdr.Reg2 == 0) {
1765                                 SysPrintf("cdrom: fixing up old savestate\n");
1766                                 cdr.Reg2 = 7;
1767                         }
1768                         // also did not save Attenuator..
1769                         if ((cdr.AttenuatorLeftToLeft | cdr.AttenuatorLeftToRight
1770                              | cdr.AttenuatorRightToLeft | cdr.AttenuatorRightToRight) == 0)
1771                         {
1772                                 cdr.AttenuatorLeftToLeft = cdr.AttenuatorRightToRight = 0x80;
1773                         }
1774                 }
1775         }
1776
1777         return 0;
1778 }
1779
1780 void LidInterrupt(void) {
1781         getCdInfo();
1782         cdrLidSeekInterrupt();
1783 }