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