core: update to newer interrupt code, seems to affect timings too
[pcsx_rearmed.git] / libpcsxcore / cdrom.c
CommitLineData
ef79bbde
P
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
27cdrStruct 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
69char *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
80unsigned char Test04[] = { 0 };
81unsigned char Test05[] = { 0 };
82unsigned char Test20[] = { 0x98, 0x06, 0x10, 0xC3 };
83unsigned char Test22[] = { 0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F };
84unsigned 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
91static struct CdrStat stat;
92static struct SubQ *subq;
93
94#define CDR_INT(eCycle) { \
d28b54b1 95 psxRegs.interrupt |= (1 << PSXINT_CDR); \
96 psxRegs.intCycle[PSXINT_CDR].cycle = eCycle; \
97 psxRegs.intCycle[PSXINT_CDR].sCycle = psxRegs.cycle; \
98 new_dyna_set_event(PSXINT_CDR, eCycle); \
ae602c19 99}
ef79bbde
P
100
101#define CDREAD_INT(eCycle) { \
d28b54b1 102 psxRegs.interrupt |= (1 << PSXINT_CDREAD); \
103 psxRegs.intCycle[PSXINT_CDREAD].cycle = eCycle; \
104 psxRegs.intCycle[PSXINT_CDREAD].sCycle = psxRegs.cycle; \
105 new_dyna_set_event(PSXINT_CDREAD, eCycle); \
ae602c19 106}
ef79bbde
P
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; \
d28b54b1 118 psxRegs.interrupt &= ~(1 << PSXINT_CDREAD); \
ef79bbde
P
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
137static 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
156void 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
165void 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
600void 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/*
687cdrRead0:
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
698unsigned 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/*
720cdrWrite0:
721 0 - to send a command / 1 - to get the result
722*/
723
724void 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
737unsigned 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
751void 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
993unsigned 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
1008void 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
1031unsigned 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
1046void 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
1079void 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
1121void cdrReset() {
1122 memset(&cdr, 0, sizeof(cdr));
1123 cdr.CurTrack = 1;
1124 cdr.File = 1;
1125 cdr.Channel = 1;
1126}
1127
1128int 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}