improved memhandlers
[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 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /* 
21 * Handles all CD-ROM registers and functions.
22 */
23
24 #include "cdrom.h"
25 #include "ppf.h"
26
27 cdrStruct cdr;
28
29 /* CD-ROM magic numbers */
30 #define CdlSync        0
31 #define CdlNop         1
32 #define CdlSetloc      2
33 #define CdlPlay        3
34 #define CdlForward     4
35 #define CdlBackward    5
36 #define CdlReadN       6
37 #define CdlStandby     7
38 #define CdlStop        8
39 #define CdlPause       9
40 #define CdlInit        10
41 #define CdlMute        11
42 #define CdlDemute      12
43 #define CdlSetfilter   13
44 #define CdlSetmode     14
45 #define CdlGetmode     15
46 #define CdlGetlocL     16
47 #define CdlGetlocP     17
48 #define CdlReadT       18
49 #define CdlGetTN       19
50 #define CdlGetTD       20
51 #define CdlSeekL       21
52 #define CdlSeekP       22
53 #define CdlSetclock    23
54 #define CdlGetclock    24
55 #define CdlTest        25
56 #define CdlID          26
57 #define CdlReadS       27
58 #define CdlReset       28
59 #define CdlReadToc     30
60
61 #define AUTOPAUSE      249
62 #define READ_ACK       250
63 #define READ           251
64 #define REPPLAY_ACK    252
65 #define REPPLAY        253
66 #define ASYNC          254
67 /* don't set 255, it's reserved */
68
69 char *CmdName[0x100]= {
70     "CdlSync",     "CdlNop",       "CdlSetloc",  "CdlPlay",
71     "CdlForward",  "CdlBackward",  "CdlReadN",   "CdlStandby",
72     "CdlStop",     "CdlPause",     "CdlInit",    "CdlMute",
73     "CdlDemute",   "CdlSetfilter", "CdlSetmode", "CdlGetmode",
74     "CdlGetlocL",  "CdlGetlocP",   "CdlReadT",   "CdlGetTN",
75     "CdlGetTD",    "CdlSeekL",     "CdlSeekP",   "CdlSetclock",
76     "CdlGetclock", "CdlTest",      "CdlID",      "CdlReadS",
77     "CdlReset",    NULL,           "CDlReadToc", NULL
78 };
79
80 unsigned char Test04[] = { 0 };
81 unsigned char Test05[] = { 0 };
82 unsigned char Test20[] = { 0x98, 0x06, 0x10, 0xC3 };
83 unsigned char Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F };
84 unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 };
85
86 // 1x = 75 sectors per second
87 // PSXCLK = 1 sec in the ps
88 // so (PSXCLK / 75) = cdr read time (linuzappz)
89 #define cdReadTime (PSXCLK / 75)
90
91 static struct CdrStat stat;
92 static struct SubQ *subq;
93
94 #define CDR_INT(eCycle) { \
95         psxRegs.interrupt |= 0x4; \
96         psxRegs.intCycle[2 + 1] = eCycle; \
97         psxRegs.intCycle[2] = psxRegs.cycle; \
98         new_dyna_set_event(0, eCycle); \
99 }
100
101 #define CDREAD_INT(eCycle) { \
102         psxRegs.interrupt |= 0x40000; \
103         psxRegs.intCycle[2 + 16 + 1] = eCycle; \
104         psxRegs.intCycle[2 + 16] = psxRegs.cycle; \
105         new_dyna_set_event(2, eCycle); \
106 }
107
108 #define StartReading(type, eCycle) { \
109         cdr.Reading = type; \
110         cdr.FirstSector = 1; \
111         cdr.Readed = 0xff; \
112         AddIrqQueue(READ_ACK, eCycle); \
113 }
114
115 #define StopReading() { \
116         if (cdr.Reading) { \
117                 cdr.Reading = 0; \
118                 psxRegs.interrupt &= ~0x40000; \
119         } \
120         cdr.StatP &= ~0x20;\
121 }
122
123 #define StopCdda() { \
124         if (cdr.Play) { \
125                 if (!Config.Cdda) CDR_stop(); \
126                 cdr.StatP &= ~0x80; \
127                 cdr.Play = FALSE; \
128         } \
129 }
130
131 #define SetResultSize(size) { \
132     cdr.ResultP = 0; \
133         cdr.ResultC = size; \
134         cdr.ResultReady = 1; \
135 }
136
137 static void ReadTrack() {
138         cdr.Prev[0] = itob(cdr.SetSector[0]);
139         cdr.Prev[1] = itob(cdr.SetSector[1]);
140         cdr.Prev[2] = itob(cdr.SetSector[2]);
141
142 #ifdef CDR_LOG
143         CDR_LOG("ReadTrack() Log: KEY *** %x:%x:%x\n", cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
144 #endif
145         cdr.RErr = CDR_readTrack(cdr.Prev);
146 }
147
148 // cdr.Stat:
149 #define NoIntr          0
150 #define DataReady       1
151 #define Complete        2
152 #define Acknowledge     3
153 #define DataEnd         4
154 #define DiskError       5
155
156 void AddIrqQueue(unsigned char irq, unsigned long ecycle) {
157         cdr.Irq = irq;
158         if (cdr.Stat) {
159                 cdr.eCycle = ecycle;
160         } else {
161                 CDR_INT(ecycle);
162         }
163 }
164
165 void cdrInterrupt() {
166         int i;
167         unsigned char Irq = cdr.Irq;
168
169         if (cdr.Stat) {
170                 CDR_INT(0x1000);
171                 return;
172         }
173
174         cdr.Irq = 0xff;
175         cdr.Ctrl &= ~0x80;
176
177         switch (Irq) {
178                 case CdlSync:
179                         SetResultSize(1);
180                         cdr.StatP |= 0x2;
181                         cdr.Result[0] = cdr.StatP;
182                         cdr.Stat = Acknowledge; 
183                         break;
184
185                 case CdlNop:
186                         SetResultSize(1);
187                         cdr.Result[0] = cdr.StatP;
188                         cdr.Stat = Acknowledge;
189                         i = stat.Status;
190                         if (CDR_getStatus(&stat) != -1) {
191                                 if (stat.Type == 0xff) cdr.Stat = DiskError;
192                                 if (stat.Status & 0x10) {
193                                         cdr.Stat = DiskError;
194                                         cdr.Result[0] |= 0x11;
195                                         cdr.Result[0] &= ~0x02;
196                                 }
197                                 else if (i & 0x10) {
198                                         cdr.StatP |= 0x2;
199                                         cdr.Result[0] |= 0x2;
200                                         CheckCdrom();
201                                 }
202                         }
203                         break;
204
205                 case CdlSetloc:
206                         cdr.CmdProcess = 0;
207                         SetResultSize(1);
208                         cdr.StatP |= 0x2;
209                         cdr.Result[0] = cdr.StatP;
210                         cdr.Stat = Acknowledge;
211                         break;
212
213                 case CdlPlay:
214                         cdr.CmdProcess = 0;
215                         SetResultSize(1);
216                         cdr.StatP |= 0x2;
217                         cdr.Result[0] = cdr.StatP;
218                         cdr.Stat = Acknowledge;
219                         cdr.StatP |= 0x80;
220 //                      if ((cdr.Mode & 0x5) == 0x5) AddIrqQueue(REPPLAY, cdReadTime);
221                         break;
222
223         case CdlForward:
224                         cdr.CmdProcess = 0;
225                         SetResultSize(1);
226                         cdr.StatP |= 0x2;
227                 cdr.Result[0] = cdr.StatP;
228                 cdr.Stat = Complete;
229                         break;
230
231         case CdlBackward:
232                         cdr.CmdProcess = 0;
233                         SetResultSize(1);
234                         cdr.StatP |= 0x2;
235                 cdr.Result[0] = cdr.StatP;
236                 cdr.Stat = Complete;
237                         break;
238
239         case CdlStandby:
240                         cdr.CmdProcess = 0;
241                         SetResultSize(1);
242                         cdr.StatP |= 0x2;
243                         cdr.Result[0] = cdr.StatP;
244                         cdr.Stat = Complete;
245                         break;
246
247                 case CdlStop:
248                         cdr.CmdProcess = 0;
249                         SetResultSize(1);
250                         cdr.StatP &= ~0x2;
251                         cdr.Result[0] = cdr.StatP;
252                         cdr.Stat = Complete;
253 //                      cdr.Stat = Acknowledge;
254
255                         // check case open/close -shalma
256                         i = stat.Status;
257                         if (CDR_getStatus(&stat) != -1) {
258                                 if (stat.Type == 0xff) cdr.Stat = DiskError;
259                                 if (stat.Status & 0x10) {
260                                         cdr.Stat = DiskError;
261                                         cdr.Result[0] |= 0x11;
262                                         cdr.Result[0] &= ~0x02;
263                                 }
264                                 else if (i & 0x10) {
265                                         cdr.StatP |= 0x2;
266                                         cdr.Result[0] |= 0x2;
267                                         CheckCdrom();
268                                 }
269                         }
270                         break;
271
272                 case CdlPause:
273                         SetResultSize(1);
274                         cdr.Result[0] = cdr.StatP;
275                 cdr.Stat = Acknowledge;
276                         AddIrqQueue(CdlPause + 0x20, 0x1000);
277                         cdr.Ctrl |= 0x80;
278                         break;
279
280                 case CdlPause + 0x20:
281                         SetResultSize(1);
282                 cdr.StatP &= ~0x20;
283                         cdr.StatP |= 0x2;
284                         cdr.Result[0] = cdr.StatP;
285                 cdr.Stat = Complete;
286                         break;
287
288         case CdlInit:
289                         SetResultSize(1);
290                 cdr.StatP = 0x2;
291                         cdr.Result[0] = cdr.StatP;
292                 cdr.Stat = Acknowledge;
293 //                      if (!cdr.Init) {
294                                 AddIrqQueue(CdlInit + 0x20, 0x1000);
295 //                      }
296                 break;
297
298                 case CdlInit + 0x20:
299                         SetResultSize(1);
300                         cdr.Result[0] = cdr.StatP;
301                 cdr.Stat = Complete;
302                         cdr.Init = 1;
303                         break;
304
305         case CdlMute:
306                         SetResultSize(1);
307                         cdr.StatP |= 0x2;
308                 cdr.Result[0] = cdr.StatP;
309                 cdr.Stat = Acknowledge;
310                         break;
311
312         case CdlDemute:
313                         SetResultSize(1);
314                         cdr.StatP |= 0x2;
315                 cdr.Result[0] = cdr.StatP;
316                 cdr.Stat = Acknowledge;
317                         break;
318
319         case CdlSetfilter:
320                         SetResultSize(1);
321                         cdr.StatP |= 0x2;
322                 cdr.Result[0] = cdr.StatP;
323                 cdr.Stat = Acknowledge; 
324                 break;
325
326                 case CdlSetmode:
327                         SetResultSize(1);
328                         cdr.StatP |= 0x2;
329                 cdr.Result[0] = cdr.StatP;
330                 cdr.Stat = Acknowledge;
331                 break;
332
333         case CdlGetmode:
334                         SetResultSize(6);
335                         cdr.StatP |= 0x2;
336                 cdr.Result[0] = cdr.StatP;
337                 cdr.Result[1] = cdr.Mode;
338                 cdr.Result[2] = cdr.File;
339                 cdr.Result[3] = cdr.Channel;
340                 cdr.Result[4] = 0;
341                 cdr.Result[5] = 0;
342                 cdr.Stat = Acknowledge;
343                 break;
344
345         case CdlGetlocL:
346                         SetResultSize(8);
347 //              for (i = 0; i < 8; i++)
348 //                              cdr.Result[i] = itob(cdr.Transfer[i]);
349                 for (i = 0; i < 8; i++)
350                                 cdr.Result[i] = cdr.Transfer[i];
351                 cdr.Stat = Acknowledge;
352                 break;
353
354                 case CdlGetlocP:
355                         SetResultSize(8);
356                         subq = (struct SubQ *)CDR_getBufferSub();
357
358                         if (subq != NULL) {
359                                 cdr.Result[0] = subq->TrackNumber;
360                                 cdr.Result[1] = subq->IndexNumber;
361                                 memcpy(cdr.Result + 2, subq->TrackRelativeAddress, 3);
362                                 memcpy(cdr.Result + 5, subq->AbsoluteAddress, 3);
363
364                                 // subQ integrity check
365                                 if (calcCrc((u8 *)subq + 12, 10) != (((u16)subq->CRC[0] << 8) | subq->CRC[1])) {
366                                         memset(cdr.Result + 2, 0, 3 + 3); // CRC wrong, wipe out time data
367                                 }
368                         } else {
369                                 cdr.Result[0] = 1;
370                                 cdr.Result[1] = 1;
371
372                                 cdr.Result[2] = btoi(cdr.Prev[0]);
373                                 cdr.Result[3] = btoi(cdr.Prev[1]) - 2;
374                                 cdr.Result[4] = cdr.Prev[2];
375
376                                 // m:s adjustment
377                                 if ((s8)cdr.Result[3] < 0) {
378                                         cdr.Result[3] += 60;
379                                         cdr.Result[2] -= 1;
380                                 }
381
382                                 cdr.Result[2] = itob(cdr.Result[2]);
383                                 cdr.Result[3] = itob(cdr.Result[3]);
384
385                                 memcpy(cdr.Result + 5, cdr.Prev, 3);
386                         }
387
388                         cdr.Stat = Acknowledge;
389                         break;
390
391         case CdlGetTN:
392                         cdr.CmdProcess = 0;
393                         SetResultSize(3);
394                         cdr.StatP |= 0x2;
395                 cdr.Result[0] = cdr.StatP;
396                 if (CDR_getTN(cdr.ResultTN) == -1) {
397                                 cdr.Stat = DiskError;
398                                 cdr.Result[0] |= 0x01;
399                 } else {
400                         cdr.Stat = Acknowledge;
401                     cdr.Result[1] = itob(cdr.ResultTN[0]);
402                     cdr.Result[2] = itob(cdr.ResultTN[1]);
403                 }
404                 break;
405
406         case CdlGetTD:
407                         cdr.CmdProcess = 0;
408                         cdr.Track = btoi(cdr.Param[0]);
409                         SetResultSize(4);
410                         cdr.StatP |= 0x2;
411                         if (CDR_getTD(cdr.Track, cdr.ResultTD) == -1) {
412                                 cdr.Stat = DiskError;
413                                 cdr.Result[0] |= 0x01;
414                         } else {
415                                 cdr.Stat = Acknowledge;
416                                 cdr.Result[0] = cdr.StatP;
417                                 cdr.Result[1] = itob(cdr.ResultTD[2]);
418                                 cdr.Result[2] = itob(cdr.ResultTD[1]);
419                                 cdr.Result[3] = itob(cdr.ResultTD[0]);
420                         }
421                         break;
422
423         case CdlSeekL:
424                         SetResultSize(1);
425                         cdr.StatP |= 0x2;
426                 cdr.Result[0] = cdr.StatP;
427                         cdr.StatP |= 0x40;
428                 cdr.Stat = Acknowledge;
429                         cdr.Seeked = TRUE;
430                         AddIrqQueue(CdlSeekL + 0x20, 0x1000);
431                         break;
432
433         case CdlSeekL + 0x20:
434                         SetResultSize(1);
435                         cdr.StatP |= 0x2;
436                         cdr.StatP &= ~0x40;
437                 cdr.Result[0] = cdr.StatP;
438                 cdr.Stat = Complete;
439                         break;
440
441         case CdlSeekP:
442                         SetResultSize(1);
443                         cdr.StatP |= 0x2;
444                 cdr.Result[0] = cdr.StatP;
445                         cdr.StatP |= 0x40;
446                 cdr.Stat = Acknowledge;
447                         AddIrqQueue(CdlSeekP + 0x20, 0x1000);
448                         break;
449
450         case CdlSeekP + 0x20:
451                         SetResultSize(1);
452                         cdr.StatP |= 0x2;
453                         cdr.StatP &= ~0x40;
454                 cdr.Result[0] = cdr.StatP;
455                 cdr.Stat = Complete;
456                         break;
457
458                 case CdlTest:
459                 cdr.Stat = Acknowledge;
460                 switch (cdr.Param[0]) {
461                     case 0x20: // System Controller ROM Version
462                                         SetResultSize(4);
463                                         memcpy(cdr.Result, Test20, 4);
464                                         break;
465                                 case 0x22:
466                                         SetResultSize(8);
467                                         memcpy(cdr.Result, Test22, 4);
468                                         break;
469                                 case 0x23: case 0x24:
470                                         SetResultSize(8);
471                                         memcpy(cdr.Result, Test23, 4);
472                                         break;
473                 }
474                         break;
475
476         case CdlID:
477                         SetResultSize(1);
478                         cdr.StatP |= 0x2;
479                 cdr.Result[0] = cdr.StatP;
480                 cdr.Stat = Acknowledge;
481                         AddIrqQueue(CdlID + 0x20, 0x1000);
482                         break;
483
484                 case CdlID + 0x20:
485                         SetResultSize(8);
486                 if (CDR_getStatus(&stat) == -1) {
487                         cdr.Result[0] = 0x00; // 0x08 and cdr.Result[1]|0x10 : audio cd, enters cd player
488                 cdr.Result[1] = 0x00; // 0x80 leads to the menu in the bios, else loads CD
489                 }
490                 else {
491                 if (stat.Type == 2) {
492                         cdr.Result[0] = 0x08;
493                     cdr.Result[1] = 0x10;
494                         }
495                         else {
496                     cdr.Result[0] = 0x00;
497                     cdr.Result[1] = 0x00;
498                         }
499                 }
500                         cdr.Result[1] |= 0x80;
501                         cdr.Result[2] = 0x00;
502                         cdr.Result[3] = 0x00;
503                         strncpy((char *)&cdr.Result[4], "PCSX", 4);
504                         cdr.Stat = Complete;
505                         break;
506
507                 case CdlReset:
508                         SetResultSize(1);
509                 cdr.StatP = 0x2;
510                         cdr.Result[0] = cdr.StatP;
511                 cdr.Stat = Acknowledge;
512                         break;
513
514         case CdlReadToc:
515                         SetResultSize(1);
516                         cdr.StatP |= 0x2;
517                 cdr.Result[0] = cdr.StatP;
518                 cdr.Stat = Acknowledge;
519                         AddIrqQueue(CdlReadToc + 0x20, 0x1000);
520                         break;
521
522         case CdlReadToc + 0x20:
523                         SetResultSize(1);
524                         cdr.StatP |= 0x2;
525                 cdr.Result[0] = cdr.StatP;
526                 cdr.Stat = Complete;
527                         break;
528
529                 case AUTOPAUSE:
530                         cdr.OCUP = 0;
531 /*                      SetResultSize(1);
532                         StopCdda();
533                         StopReading();
534                         cdr.OCUP = 0;
535                 cdr.StatP&=~0x20;
536                         cdr.StatP|= 0x2;
537                 cdr.Result[0] = cdr.StatP;
538                 cdr.Stat = DataEnd;
539 */                      AddIrqQueue(CdlPause, 0x800);
540                         break;
541
542                 case READ_ACK:
543                         if (!cdr.Reading) return;
544
545                         SetResultSize(1);
546                         cdr.StatP |= 0x2;
547                 cdr.Result[0] = cdr.StatP;
548                         if (!cdr.Seeked) {
549                                 cdr.Seeked = TRUE;
550                                 cdr.StatP |= 0x40;
551                         }
552                         cdr.StatP |= 0x20;
553                 cdr.Stat = Acknowledge;
554
555 //                      CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
556                         CDREAD_INT(0x80000);
557                         break;
558
559                 case REPPLAY_ACK:
560                         cdr.Stat = Acknowledge;
561                         cdr.Result[0] = cdr.StatP;
562                         SetResultSize(1);
563                         AddIrqQueue(REPPLAY, cdReadTime);
564                         break;
565
566                 case REPPLAY: 
567                         if ((cdr.Mode & 5) != 5) break;
568 /*                      if (CDR_getStatus(&stat) == -1) {
569                                 cdr.Result[0] = 0;
570                                 cdr.Result[1] = 0;
571                                 cdr.Result[2] = 0;
572                                 cdr.Result[3] = 0;
573                                 cdr.Result[4] = 0;
574                                 cdr.Result[5] = 0;
575                                 cdr.Result[6] = 0;
576                                 cdr.Result[7] = 0;
577                         } else memcpy(cdr.Result, &stat.Track, 8);
578                         cdr.Stat = 1;
579                         SetResultSize(8);
580                         AddIrqQueue(REPPLAY_ACK, cdReadTime);
581 */                      break;
582
583                 case 0xff:
584                         return;
585
586                 default:
587                         cdr.Stat = Complete;
588                         break;
589         }
590
591         if (cdr.Stat != NoIntr && cdr.Reg2 != 0x18) {
592                 psxHu32ref(0x1070) |= SWAP32((u32)0x4);
593         }
594
595 #ifdef CDR_LOG
596         CDR_LOG("cdrInterrupt() Log: CDR Interrupt IRQ %x\n", Irq);
597 #endif
598 }
599
600 void cdrReadInterrupt() {
601         u8 *buf;
602
603         if (!cdr.Reading)
604                 return;
605
606         if (cdr.Stat) {
607                 CDREAD_INT(0x1000);
608                 return;
609         }
610
611 #ifdef CDR_LOG
612         CDR_LOG("cdrReadInterrupt() Log: KEY END");
613 #endif
614
615     cdr.OCUP = 1;
616         SetResultSize(1);
617         cdr.StatP |= 0x22;
618         cdr.StatP &= ~0x40;
619     cdr.Result[0] = cdr.StatP;
620
621         ReadTrack();
622
623         buf = CDR_getBuffer();
624         if (buf == NULL)
625                 cdr.RErr = -1;
626
627         if (cdr.RErr == -1) {
628 #ifdef CDR_LOG
629                 fprintf(emuLog, "cdrReadInterrupt() Log: err\n");
630 #endif
631                 memset(cdr.Transfer, 0, DATA_SIZE);
632                 cdr.Stat = DiskError;
633                 cdr.Result[0] |= 0x01;
634                 CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
635                 return;
636         }
637
638         memcpy(cdr.Transfer, buf, DATA_SIZE);
639         CheckPPFCache(cdr.Transfer, cdr.Prev[0], cdr.Prev[1], cdr.Prev[2]);
640
641     cdr.Stat = DataReady;
642
643 #ifdef CDR_LOG
644         fprintf(emuLog, "cdrReadInterrupt() Log: cdr.Transfer %x:%x:%x\n", cdr.Transfer[0], cdr.Transfer[1], cdr.Transfer[2]);
645 #endif
646
647         if ((!cdr.Muted) && (cdr.Mode & 0x40) && (!Config.Xa) && (cdr.FirstSector != -1)) { // CD-XA
648                 if ((cdr.Transfer[4 + 2] & 0x4) &&
649                         ((cdr.Mode & 0x8) ? (cdr.Transfer[4 + 1] == cdr.Channel) : 1) &&
650                         (cdr.Transfer[4 + 0] == cdr.File)) {
651                         int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector);
652
653                         if (!ret) {
654                                 SPU_playADPCMchannel(&cdr.Xa);
655                                 cdr.FirstSector = 0;
656                         }
657                         else cdr.FirstSector = -1;
658                 }
659         }
660
661         cdr.SetSector[2]++;
662     if (cdr.SetSector[2] == 75) {
663         cdr.SetSector[2] = 0;
664         cdr.SetSector[1]++;
665         if (cdr.SetSector[1] == 60) {
666             cdr.SetSector[1] = 0;
667             cdr.SetSector[0]++;
668         }
669     }
670
671     cdr.Readed = 0;
672
673         if ((cdr.Transfer[4 + 2] & 0x80) && (cdr.Mode & 0x2)) { // EOF
674 #ifdef CDR_LOG
675                 CDR_LOG("cdrReadInterrupt() Log: Autopausing read\n");
676 #endif
677 //              AddIrqQueue(AUTOPAUSE, 0x1000);
678                 AddIrqQueue(CdlPause, 0x1000);
679         }
680         else {
681                 CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
682         }
683         psxHu32ref(0x1070) |= SWAP32((u32)0x4);
684 }
685
686 /*
687 cdrRead0:
688         bit 0 - 0 REG1 command send / 1 REG1 data read
689         bit 1 - 0 data transfer finish / 1 data transfer ready/in progress
690         bit 2 - unknown
691         bit 3 - unknown
692         bit 4 - unknown
693         bit 5 - 1 result ready
694         bit 6 - 1 dma ready
695         bit 7 - 1 command being processed
696 */
697
698 unsigned char cdrRead0(void) {
699         if (cdr.ResultReady)
700                 cdr.Ctrl |= 0x20;
701         else
702                 cdr.Ctrl &= ~0x20;
703
704         if (cdr.OCUP)
705                 cdr.Ctrl |= 0x40;
706 //  else
707 //              cdr.Ctrl &= ~0x40;
708
709         // What means the 0x10 and the 0x08 bits? I only saw it used by the bios
710         cdr.Ctrl |= 0x18;
711
712 #ifdef CDR_LOG
713         CDR_LOG("cdrRead0() Log: CD0 Read: %x\n", cdr.Ctrl);
714 #endif
715
716         return psxHu8(0x1800) = cdr.Ctrl;
717 }
718
719 /*
720 cdrWrite0:
721         0 - to send a command / 1 - to get the result
722 */
723
724 void cdrWrite0(unsigned char rt) {
725 #ifdef CDR_LOG
726         CDR_LOG("cdrWrite0() Log: CD0 write: %x\n", rt);
727 #endif
728         cdr.Ctrl = rt | (cdr.Ctrl & ~0x3);
729
730     if (rt == 0) {
731                 cdr.ParamP = 0;
732                 cdr.ParamC = 0;
733                 cdr.ResultReady = 0;
734         }
735 }
736
737 unsigned char cdrRead1(void) {
738     if (cdr.ResultReady) { // && cdr.Ctrl & 0x1) {
739                 psxHu8(0x1801) = cdr.Result[cdr.ResultP++];
740                 if (cdr.ResultP == cdr.ResultC)
741                         cdr.ResultReady = 0;
742         } else {
743                 psxHu8(0x1801) = 0;
744         }
745 #ifdef CDR_LOG
746         CDR_LOG("cdrRead1() Log: CD1 Read: %x\n", psxHu8(0x1801));
747 #endif
748         return psxHu8(0x1801);
749 }
750
751 void cdrWrite1(unsigned char rt) {
752         int i;
753
754 #ifdef CDR_LOG
755         CDR_LOG("cdrWrite1() Log: CD1 write: %x (%s)\n", rt, CmdName[rt]);
756 #endif
757 //      psxHu8(0x1801) = rt;
758     cdr.Cmd = rt;
759         cdr.OCUP = 0;
760
761 #ifdef CDRCMD_DEBUG
762         SysPrintf("cdrWrite1() Log: CD1 write: %x (%s)", rt, CmdName[rt]);
763         if (cdr.ParamC) {
764                 SysPrintf(" Param[%d] = {", cdr.ParamC);
765                 for (i = 0; i < cdr.ParamC; i++)
766                         SysPrintf(" %x,", cdr.Param[i]);
767                 SysPrintf("}\n");
768         } else {
769                 SysPrintf("\n");
770         }
771 #endif
772
773         if (cdr.Ctrl & 0x1) return;
774
775     switch (cdr.Cmd) {
776         case CdlSync:
777                         cdr.Ctrl |= 0x80;
778                 cdr.Stat = NoIntr; 
779                 AddIrqQueue(cdr.Cmd, 0x1000);
780                 break;
781
782         case CdlNop:
783                         cdr.Ctrl |= 0x80;
784                 cdr.Stat = NoIntr; 
785                 AddIrqQueue(cdr.Cmd, 0x1000);
786                 break;
787
788         case CdlSetloc:
789                         StopReading();
790                         cdr.Seeked = FALSE;
791                 for (i = 0; i < 3; i++)
792                                 cdr.SetSector[i] = btoi(cdr.Param[i]);
793                 cdr.SetSector[3] = 0;
794 /*              if ((cdr.SetSector[0] | cdr.SetSector[1] | cdr.SetSector[2]) == 0) {
795                                 *(u32 *)cdr.SetSector = *(u32 *)cdr.SetSectorSeek;
796                         }*/
797                         cdr.Ctrl |= 0x80;
798                 cdr.Stat = NoIntr;
799                 AddIrqQueue(cdr.Cmd, 0x1000);
800                 break;
801
802         case CdlPlay:
803                 if (!cdr.SetSector[0] & !cdr.SetSector[1] & !cdr.SetSector[2]) {
804                 if (CDR_getTN(cdr.ResultTN) != -1) {
805                         if (cdr.CurTrack > cdr.ResultTN[1])
806                                                 cdr.CurTrack = cdr.ResultTN[1];
807                     if (CDR_getTD((unsigned char)(cdr.CurTrack), cdr.ResultTD) != -1) {
808                                 int tmp = cdr.ResultTD[2];
809                         cdr.ResultTD[2] = cdr.ResultTD[0];
810                                                 cdr.ResultTD[0] = tmp;
811                             if (!Config.Cdda) CDR_play(cdr.ResultTD);
812                                         }
813                 }
814                         } else if (!Config.Cdda) {
815                                 CDR_play(cdr.SetSector);
816                         }
817                 cdr.Play = TRUE;
818                         cdr.Ctrl |= 0x80;
819                 cdr.Stat = NoIntr; 
820                 AddIrqQueue(cdr.Cmd, 0x1000);
821                 break;
822
823         case CdlForward:
824                 if (cdr.CurTrack < 0xaa)
825                                 cdr.CurTrack++;
826                         cdr.Ctrl |= 0x80;
827                 cdr.Stat = NoIntr; 
828                 AddIrqQueue(cdr.Cmd, 0x1000);
829                 break;
830
831         case CdlBackward:
832                 if (cdr.CurTrack > 1)
833                                 cdr.CurTrack--;
834                         cdr.Ctrl |= 0x80;
835                 cdr.Stat = NoIntr; 
836                 AddIrqQueue(cdr.Cmd, 0x1000);
837                 break;
838
839         case CdlReadN:
840                         cdr.Irq = 0;
841                         StopReading();
842                         cdr.Ctrl|= 0x80;
843                 cdr.Stat = NoIntr; 
844                         StartReading(1, 0x1000);
845                 break;
846
847         case CdlStandby:
848                         StopCdda();
849                         StopReading();
850                         cdr.Ctrl |= 0x80;
851                 cdr.Stat = NoIntr;
852                 AddIrqQueue(cdr.Cmd, 0x1000);
853                 break;
854
855         case CdlStop:
856                         StopCdda();
857                         StopReading();
858                         cdr.Ctrl |= 0x80;
859                 cdr.Stat = NoIntr;
860                 AddIrqQueue(cdr.Cmd, 0x1000);
861                 break;
862
863         case CdlPause:
864                         StopCdda();
865                         StopReading();
866                         cdr.Ctrl |= 0x80;
867                 cdr.Stat = NoIntr;
868                 AddIrqQueue(cdr.Cmd, 0x80000);
869                 break;
870
871                 case CdlReset:
872         case CdlInit:
873                         StopCdda();
874                         StopReading();
875                         cdr.Ctrl |= 0x80;
876                 cdr.Stat = NoIntr; 
877                 AddIrqQueue(cdr.Cmd, 0x1000);
878                 break;
879
880         case CdlMute:
881                 cdr.Muted = TRUE;
882                         cdr.Ctrl |= 0x80;
883                 cdr.Stat = NoIntr; 
884                 AddIrqQueue(cdr.Cmd, 0x1000);
885                 break;
886
887         case CdlDemute:
888                 cdr.Muted = FALSE;
889                         cdr.Ctrl |= 0x80;
890                 cdr.Stat = NoIntr; 
891                 AddIrqQueue(cdr.Cmd, 0x1000);
892                 break;
893
894         case CdlSetfilter:
895                 cdr.File = cdr.Param[0];
896                 cdr.Channel = cdr.Param[1];
897                         cdr.Ctrl |= 0x80;
898                 cdr.Stat = NoIntr; 
899                 AddIrqQueue(cdr.Cmd, 0x1000);
900                 break;
901
902         case CdlSetmode:
903 #ifdef CDR_LOG
904                         CDR_LOG("cdrWrite1() Log: Setmode %x\n", cdr.Param[0]);
905 #endif 
906                 cdr.Mode = cdr.Param[0];
907                         cdr.Ctrl |= 0x80;
908                 cdr.Stat = NoIntr; 
909                 AddIrqQueue(cdr.Cmd, 0x1000);
910                 break;
911
912         case CdlGetmode:
913                         cdr.Ctrl |= 0x80;
914                 cdr.Stat = NoIntr; 
915                 AddIrqQueue(cdr.Cmd, 0x1000);
916                 break;
917
918         case CdlGetlocL:
919                         cdr.Ctrl |= 0x80;
920                 cdr.Stat = NoIntr; 
921                 AddIrqQueue(cdr.Cmd, 0x1000);
922                 break;
923
924         case CdlGetlocP:
925                         cdr.Ctrl |= 0x80;
926                 cdr.Stat = NoIntr; 
927                         AddIrqQueue(cdr.Cmd, 0x1000);
928                 break;
929
930         case CdlGetTN:
931                         cdr.Ctrl |= 0x80;
932                 cdr.Stat = NoIntr; 
933                 AddIrqQueue(cdr.Cmd, 0x1000);
934                 break;
935
936         case CdlGetTD:
937                         cdr.Ctrl |= 0x80;
938                 cdr.Stat = NoIntr; 
939                 AddIrqQueue(cdr.Cmd, 0x1000);
940                 break;
941
942         case CdlSeekL:
943 //                      ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0];
944                         cdr.Ctrl |= 0x80;
945                 cdr.Stat = NoIntr; 
946                 AddIrqQueue(cdr.Cmd, 0x1000);
947                 break;
948
949         case CdlSeekP:
950 //              ((u32 *)cdr.SetSectorSeek)[0] = ((u32 *)cdr.SetSector)[0];
951                         cdr.Ctrl |= 0x80;
952                 cdr.Stat = NoIntr; 
953                 AddIrqQueue(cdr.Cmd, 0x1000);
954                 break;
955
956         case CdlTest:
957                         cdr.Ctrl |= 0x80;
958                 cdr.Stat = NoIntr; 
959                 AddIrqQueue(cdr.Cmd, 0x1000);
960                 break;
961
962         case CdlID:
963                         cdr.Ctrl |= 0x80;
964                 cdr.Stat = NoIntr; 
965                 AddIrqQueue(cdr.Cmd, 0x1000);
966                 break;
967
968         case CdlReadS:
969                         cdr.Irq = 0;
970                         StopReading();
971                         cdr.Ctrl |= 0x80;
972                 cdr.Stat = NoIntr; 
973                         StartReading(2, 0x1000);
974                 break;
975
976         case CdlReadToc:
977                         cdr.Ctrl |= 0x80;
978                 cdr.Stat = NoIntr; 
979                 AddIrqQueue(cdr.Cmd, 0x1000);
980                 break;
981
982         default:
983 #ifdef CDR_LOG
984                         CDR_LOG("cdrWrite1() Log: Unknown command: %x\n", cdr.Cmd);
985 #endif
986                         return;
987     }
988         if (cdr.Stat != NoIntr) {
989                 psxHu32ref(0x1070) |= SWAP32((u32)0x4);
990         }
991 }
992
993 unsigned char cdrRead2(void) {
994         unsigned char ret;
995
996         if (cdr.Readed == 0) {
997                 ret = 0;
998         } else {
999                 ret = *cdr.pTransfer++;
1000         }
1001
1002 #ifdef CDR_LOG
1003         CDR_LOG("cdrRead2() Log: CD2 Read: %x\n", ret);
1004 #endif
1005         return ret;
1006 }
1007
1008 void cdrWrite2(unsigned char rt) {
1009 #ifdef CDR_LOG
1010         CDR_LOG("cdrWrite2() Log: CD2 write: %x\n", rt);
1011 #endif
1012     if (cdr.Ctrl & 0x1) {
1013                 switch (rt) {
1014                         case 0x07:
1015                         cdr.ParamP = 0;
1016                                 cdr.ParamC = 0;
1017                                 cdr.ResultReady = 1; //0;
1018                                 cdr.Ctrl &= ~3; //cdr.Ctrl = 0;
1019                                 break;
1020
1021                         default:
1022                                 cdr.Reg2 = rt;
1023                                 break;
1024                 }
1025     } else if (!(cdr.Ctrl & 0x1) && cdr.ParamP < 8) {
1026                 cdr.Param[cdr.ParamP++] = rt;
1027                 cdr.ParamC++;
1028         }
1029 }
1030
1031 unsigned char cdrRead3(void) {
1032         if (cdr.Stat) {
1033                 if (cdr.Ctrl & 0x1)
1034                         psxHu8(0x1803) = cdr.Stat | 0xE0;
1035                 else
1036                         psxHu8(0x1803) = 0xff;
1037         } else {
1038                 psxHu8(0x1803) = 0;
1039         }
1040 #ifdef CDR_LOG
1041         CDR_LOG("cdrRead3() Log: CD3 Read: %x\n", psxHu8(0x1803));
1042 #endif
1043         return psxHu8(0x1803);
1044 }
1045
1046 void cdrWrite3(unsigned char rt) {
1047 #ifdef CDR_LOG
1048         CDR_LOG("cdrWrite3() Log: CD3 write: %x\n", rt);
1049 #endif
1050     if (rt == 0x07 && cdr.Ctrl & 0x1) {
1051                 cdr.Stat = 0;
1052
1053                 if (cdr.Irq == 0xff) {
1054                         cdr.Irq = 0;
1055                         return;
1056                 }
1057                 if (cdr.Irq)
1058                         CDR_INT(cdr.eCycle);
1059                 if (cdr.Reading && !cdr.ResultReady) 
1060             CDREAD_INT((cdr.Mode & 0x80) ? (cdReadTime / 2) : cdReadTime);
1061
1062                 return;
1063         }
1064         if (rt == 0x80 && !(cdr.Ctrl & 0x1) && cdr.Readed == 0) {
1065                 cdr.Readed = 1;
1066                 cdr.pTransfer = cdr.Transfer;
1067
1068                 switch (cdr.Mode & 0x30) {
1069                         case 0x10:
1070                         case 0x00:
1071                                 cdr.pTransfer += 12;
1072                                 break;
1073                         default:
1074                                 break;
1075                 }
1076         }
1077 }
1078
1079 void psxDma3(u32 madr, u32 bcr, u32 chcr) {
1080         u32 cdsize;
1081         u8 *ptr;
1082
1083 #ifdef CDR_LOG
1084         CDR_LOG("psxDma3() Log: *** DMA 3 *** %x addr = %x size = %x\n", chcr, madr, bcr);
1085 #endif
1086
1087         switch (chcr) {
1088                 case 0x11000000:
1089                 case 0x11400100:
1090                         if (cdr.Readed == 0) {
1091 #ifdef CDR_LOG
1092                                 CDR_LOG("psxDma3() Log: *** DMA 3 *** NOT READY\n");
1093 #endif
1094                                 break;
1095                         }
1096
1097                         cdsize = (bcr & 0xffff) * 4;
1098
1099                         ptr = (u8 *)PSXM(madr);
1100                         if (ptr == NULL) {
1101 #ifdef CPU_LOG
1102                                 CDR_LOG("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n");
1103 #endif
1104                                 break;
1105                         }
1106                         memcpy(ptr, cdr.pTransfer, cdsize);
1107                         psxCpu->Clear(madr, cdsize / 4);
1108                         cdr.pTransfer += cdsize;
1109                         break;
1110                 default:
1111 #ifdef CDR_LOG
1112                         CDR_LOG("psxDma3() Log: Unknown cddma %x\n", chcr);
1113 #endif
1114                         break;
1115         }
1116
1117         HW_DMA3_CHCR &= SWAP32(~0x01000000);
1118         DMA_INTERRUPT(3);
1119 }
1120
1121 void cdrReset() {
1122         memset(&cdr, 0, sizeof(cdr));
1123         cdr.CurTrack = 1;
1124         cdr.File = 1;
1125         cdr.Channel = 1;
1126 }
1127
1128 int cdrFreeze(gzFile f, int Mode) {
1129         uintptr_t tmp;
1130
1131         gzfreeze(&cdr, sizeof(cdr));
1132
1133         if (Mode == 1)
1134                 tmp = cdr.pTransfer - cdr.Transfer;
1135
1136         gzfreeze(&tmp, sizeof(tmp));
1137
1138         if (Mode == 0)
1139                 cdr.pTransfer = cdr.Transfer + tmp;
1140
1141         return 0;
1142 }