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