@@ -38,6 +38,9 @@ namespace {
38
38
39
39
using namespace std ::literals;
40
40
41
+ // The buffer/decoder chip the PSX CPU will talk to is the CXD1199, which
42
+ // datasheet can be found at https://archive.org/details/cxd-1199
43
+
41
44
class CDRomImpl final : public PCSX::CDRom {
42
45
enum Commands {
43
46
CdlSync = 0 ,
@@ -104,14 +107,14 @@ class CDRomImpl final : public PCSX::CDRom {
104
107
m_seed = 9223521712174600777ull ;
105
108
m_dataFIFOIndex = 0 ;
106
109
m_dataFIFOSize = 0 ;
107
- m_registerIndex = 0 ;
110
+ m_registerAddress = 0 ;
108
111
m_currentPosition.reset ();
109
112
m_seekPosition.reset ();
110
113
m_speed = Speed::Simple;
111
114
m_speedChanged = false ;
112
115
m_status = Status::Idle;
113
116
m_dataRequested = false ;
114
- m_causeMask = 0x1f ;
117
+ m_interruptCauseMask = 0x1f ;
115
118
m_subheaderFilter = false ;
116
119
m_realtime = false ;
117
120
m_commandFifo.clear ();
@@ -279,7 +282,7 @@ class CDRomImpl final : public PCSX::CDRom {
279
282
void maybeTriggerIRQ (Cause cause, QueueElement &element) {
280
283
uint8_t causeValue = static_cast <uint8_t >(cause);
281
284
uint8_t bit = 1 << (causeValue - 1 );
282
- if (m_causeMask & bit) {
285
+ if (m_interruptCauseMask & bit) {
283
286
element.setValue (cause);
284
287
bool actuallyTriggering = false ;
285
288
if (maybeEnqueueResponse (element)) {
@@ -329,15 +332,49 @@ class CDRomImpl final : public PCSX::CDRom {
329
332
}
330
333
331
334
uint8_t read0 () override {
332
- uint8_t v01 = m_registerIndex & 3 ;
333
- uint8_t adpcmPlaying = 0 ;
334
- uint8_t v3 = m_commandFifo. isPayloadEmpty () ? 0x08 : 0 ;
335
- uint8_t v4 = !m_commandFifo. isPayloadFull () ? 0x10 : 0 ;
336
- uint8_t v5 = !m_responseFifo[ 0 ]. isPayloadEmpty () ? 0x20 : 0 ;
337
- uint8_t v6 = m_dataFIFOSize != m_dataFIFOIndex ? 0x40 : 0 ;
335
+ // HSTS (host status) register
336
+ /*
337
+ bit 7: BUSYSTS (busy status)
338
+ This is high when the host writes a command into the command register and low when the sub
339
+ CPU sets the CLRBUSY bit (bit 6) of the CLRCTL register.
340
+ */
338
341
uint8_t v7 = m_commandFifo.hasValue ? 0x80 : 0 ;
339
-
340
- uint8_t ret = v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7;
342
+ /*
343
+ bit 6: DRQSTS (data request status)
344
+ Indicates to the host that the buffer memory data transfer request status is established. When
345
+ transferring data in the I/O mode, the host should confirm that this bit is high before accessing the
346
+ WRDATA or RDDATA register.
347
+ */
348
+ uint8_t v6 = m_dataFIFOSize != m_dataFIFOIndex ? 0x40 : 0 ;
349
+ /*
350
+ bit 5: RSLRRDY (result read ready)
351
+ The result register is not empty when this bit is high. At this time, the host can read the result
352
+ register.
353
+ */
354
+ uint8_t v5 = !m_responseFifo[0 ].isPayloadEmpty () ? 0x20 : 0 ;
355
+ /*
356
+ bit 4: PRMWRDY (parameter write ready)
357
+ The PARAMETER register is not full when this bit is high. At this time, the host writes data into the
358
+ PARAMETER register.
359
+ */
360
+ uint8_t v4 = !m_commandFifo.isPayloadFull () ? 0x10 : 0 ;
361
+ /*
362
+ bit 3: PRMEMPT (parameter empty)
363
+ The PARAMETER register is empty when this bit is high.
364
+ */
365
+ uint8_t v3 = m_commandFifo.isPayloadEmpty () ? 0x08 : 0 ;
366
+ /*
367
+ bit 2: ADPBUSY (ADPCM busy)
368
+ This bit is set high for ADPCM decoding.
369
+ */
370
+ uint8_t v2 = 0 ; /* adpcmPlaying */
371
+ /*
372
+ bits 1, 0: RA1, 0
373
+ The values of the RA1 and 0 bits for the ADDRESS register can be read from these bits.
374
+ */
375
+ uint8_t v01 = m_registerAddress & 3 ;
376
+
377
+ uint8_t ret = v01 | v2 | v3 | v4 | v5 | v6 | v7;
341
378
const bool debug = PCSX::g_emulator->settings .get <PCSX::Emulator::SettingDebugSettings>()
342
379
.get <PCSX::Emulator::DebugSettings::LoggingHWCDROM>();
343
380
if (debug) {
@@ -349,6 +386,7 @@ class CDRomImpl final : public PCSX::CDRom {
349
386
}
350
387
351
388
uint8_t read1 () override {
389
+ // RESULT
352
390
uint8_t ret = m_responseFifo[0 ].readPayloadByte ();
353
391
maybeScheduleNextCommand ();
354
392
@@ -362,6 +400,7 @@ class CDRomImpl final : public PCSX::CDRom {
362
400
}
363
401
364
402
uint8_t read2 () override {
403
+ // RD DATA
365
404
uint8_t ret = 0 ;
366
405
if (!dataFIFOHasData ()) {
367
406
ret = 0 ;
@@ -379,35 +418,53 @@ class CDRomImpl final : public PCSX::CDRom {
379
418
}
380
419
381
420
uint8_t read3 () override {
421
+ /*
422
+ * bit 4: BFWRDY (buffer write ready)
423
+ * The BFWRDY status is established if there is area where writing is possible in the buffer of 1 sector
424
+ * or more for sound map playback. It is established in any of the following cases:
425
+ * (1) When the host has set the SMEN bit (bit 5) of the HCHPCTL register high
426
+ * (2) When there is sound map data area of 1 sector or more in the buffer memory (when the buffer
427
+ * is not full) after the sound map data equivalent to 1 sector from the host has been written into
428
+ * the buffer memory
429
+ * (3) When an area for writing the sound map data has been created in the buffer memory by the
430
+ * completion of the sound map ADPCM decoding of one sector
431
+ * bit 3: BFEMPT (buffer empty)
432
+ * The BFEMPT status is established when there is no more sector data in the buffer memory upon
433
+ * completion of the sound map ADPCM decoding of one sector for sound map playback.
434
+ * bits 2 to 0: INTSTS#2 to 0
435
+ * The values of these bits are those of the corresponding bits for the sub CPU HIFCTL register.
436
+ */
437
+
382
438
uint8_t ret = 0 ;
383
- switch (m_registerIndex & 1 ) {
439
+ switch (m_registerAddress & 1 ) {
384
440
case 0 : {
385
- ret = m_causeMask | 0xe0 ;
441
+ // HINT MSK (host interrupt mask)
442
+ ret = m_interruptCauseMask;
386
443
} break ;
387
444
case 1 : {
388
- // cause
389
- // TODO: add bit 4
390
- ret = m_responseFifo[0 ].getValue () | 0xe0 ;
445
+ // HINT STS (host interrupt status)
446
+ ret = m_responseFifo[0 ].getValue ();
391
447
} break ;
392
448
}
393
449
const bool debug = PCSX::g_emulator->settings .get <PCSX::Emulator::SettingDebugSettings>()
394
450
.get <PCSX::Emulator::DebugSettings::LoggingHWCDROM>();
395
451
if (debug) {
396
452
auto ®s = PCSX::g_emulator->m_cpu ->m_regs ;
397
453
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: %08x.%08x] r3.%i: %02x\n " , regs.pc , regs.cycle ,
398
- m_registerIndex & 1 , ret);
454
+ m_registerAddress & 1 , ret);
399
455
}
400
- return ret;
456
+ return ret | 0xe0 ;
401
457
}
402
458
403
459
void write0 (uint8_t value) override {
460
+ // ADDRESS
404
461
const bool debug = PCSX::g_emulator->settings .get <PCSX::Emulator::SettingDebugSettings>()
405
462
.get <PCSX::Emulator::DebugSettings::LoggingHWCDROM>();
406
463
if (debug) {
407
464
auto ®s = PCSX::g_emulator->m_cpu ->m_regs ;
408
465
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: %08x.%08x] w0: %02x\n " , regs.pc , regs.cycle , value);
409
466
}
410
- m_registerIndex = value & 3 ;
467
+ m_registerAddress = value & 3 ;
411
468
}
412
469
413
470
void write1 (uint8_t value) override {
@@ -416,10 +473,11 @@ class CDRomImpl final : public PCSX::CDRom {
416
473
if (debug) {
417
474
auto ®s = PCSX::g_emulator->m_cpu ->m_regs ;
418
475
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: %08x.%08x] w1.%i: %02x\n " , regs.pc , regs.cycle ,
419
- m_registerIndex , value);
476
+ m_registerAddress , value);
420
477
}
421
- switch (m_registerIndex ) {
478
+ switch (m_registerAddress ) {
422
479
case 0 :
480
+ // COMMAND
423
481
m_commandFifo.value = value;
424
482
if (!m_commandFifo.hasValue ) {
425
483
if (PCSX::g_emulator->settings .get <PCSX::Emulator::SettingDebugSettings>()
@@ -431,18 +489,35 @@ class CDRomImpl final : public PCSX::CDRom {
431
489
m_commandFifo.hasValue = true ;
432
490
break ;
433
491
case 1 : {
434
- // ??
492
+ // WR DATA
435
493
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: w1:1 not available yet\n " );
436
494
PCSX::g_system->pause ();
437
495
} break ;
438
496
case 2 : {
439
- // ??
497
+ /*
498
+ CI (coding information)
499
+ This sets the coding information for sound map playback. The bit allocation is the same as that for the
500
+ coding information bytes of the sub header.
501
+ bits 7, 5, 3, 1: Reserved
502
+ bit 6: EMPHASIS
503
+ High: Emphasis ON
504
+ Low : Emphasis OFF
505
+ bit 4: BITLNGTH
506
+ High: 8 bits
507
+ Low : 4 bits
508
+ bit 2: FS
509
+ High: 18.9 kHz
510
+ Low : 37.8 kHz
511
+ bit 0: S/M (stereo/mono)
512
+ High: Stereo
513
+ Low : Mono
514
+ */
440
515
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: w1:2 not available yet\n " );
441
516
PCSX::g_system->pause ();
442
517
} break ;
443
518
case 3 : {
444
- // Volume setting RR
445
- PCSX::g_system-> log (PCSX::LogClass::CDROM, " CD-Rom: w1:3 not available yet \n " ) ;
519
+ // ATV2 Right-to-Right
520
+ m_atv[ 2 ] = value ;
446
521
} break ;
447
522
}
448
523
}
@@ -453,22 +528,24 @@ class CDRomImpl final : public PCSX::CDRom {
453
528
if (debug) {
454
529
auto ®s = PCSX::g_emulator->m_cpu ->m_regs ;
455
530
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: %08x.%08x] w2.%i: %02x\n " , regs.pc , regs.cycle ,
456
- m_registerIndex , value);
531
+ m_registerAddress , value);
457
532
}
458
- switch (m_registerIndex ) {
533
+ switch (m_registerAddress ) {
459
534
case 0 : {
535
+ // PARAMETER
460
536
m_commandFifo.pushPayloadData (value);
461
537
} break ;
462
538
case 1 : {
463
- m_causeMask = value;
539
+ // HINT MSK (host interrupt mask)
540
+ m_interruptCauseMask = value;
464
541
} break ;
465
542
case 2 : {
466
- // Volume setting LL
467
- PCSX::g_system-> log (PCSX::LogClass::CDROM, " CD-Rom: w2:2 not available yet \n " ) ;
543
+ // ATV0 Left-to-Left
544
+ m_atv[ 0 ] = value ;
468
545
} break ;
469
546
case 3 : {
470
- // Volume setting RL
471
- PCSX::g_system-> log (PCSX::LogClass::CDROM, " CD-Rom: w2:3 not available yet \n " ) ;
547
+ // ATV3 Right-to-Left
548
+ m_atv[ 3 ] = value ;
472
549
} break ;
473
550
}
474
551
}
@@ -479,11 +556,25 @@ class CDRomImpl final : public PCSX::CDRom {
479
556
if (debug) {
480
557
auto ®s = PCSX::g_emulator->m_cpu ->m_regs ;
481
558
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: %08x.%08x] w3.%i: %02x\n " , regs.pc , regs.cycle ,
482
- m_registerIndex , value);
559
+ m_registerAddress , value);
483
560
}
484
- switch (m_registerIndex ) {
561
+ switch (m_registerAddress ) {
485
562
case 0 : {
486
- // ??
563
+ // clang-format off
564
+ /*
565
+ HCHPCTL (host chip control) register
566
+ bit 7: BFRD (buffer read)
567
+ The transfer of (drive) data from the buffer memory to the host is started by setting this bit high.
568
+ The bit is automatically set low upon completion of the transfer.
569
+ bit 6: BFWR (buffer write)
570
+ The transfer of data from the host to the buffer memory is started by setting this bit high. The bit is
571
+ automatically set low upon completion of the transfer.
572
+ bit 5: SMEN (sound map En)
573
+ This is set high to perform sound map ADPCM playback. */
574
+ // clang-format on
575
+ bool bfrd = value & 0x80 ;
576
+ bool bfwr = value & 0x40 ;
577
+ bool smen = value & 0x20 ;
487
578
if (value == 0 ) {
488
579
m_dataRequested = false ;
489
580
m_dataFIFOSize = 0 ;
@@ -499,6 +590,35 @@ class CDRomImpl final : public PCSX::CDRom {
499
590
PCSX::g_system->pause ();
500
591
} break ;
501
592
case 1 : {
593
+ // clang-format off
594
+ /*
595
+ HCLRCTL (host clear control)
596
+ When each bit of this register is set high, the chip, status, register, interrupt status and interrupt request to
597
+ the host generated by the status are cleared.
598
+ bit 7: CHPRST (chip reset)
599
+ The inside of the IC is initialized by setting this bit high. The bit is automatically set low upon
600
+ completion of the initialization of the IC. There is therefore no need for the host to reset low. When
601
+ the inside of the IC is initialized by setting bit high, the XHRS pin is set low.
602
+ bit 6: CLRPRM (clear parameter)
603
+ The parameter register is cleared by setting this bit high. The bit is automatically set low upon
604
+ completion of the clearing for the parameter register. There is therefore no need for the host to
605
+ reset low.
606
+ bit 5: SMADPCLR (sound map ADPCM clear)
607
+ This bit is set high to terminate sound map ADPCM decoding forcibly.
608
+ (1) When this bit has been set high for sound map ADPCM playback (when both SMEN and
609
+ ADPBSY (HSTS register bit 2) are high):
610
+ • ADPCM decoding during playback is suspended. (Noise may be generated).
611
+ • The sound map and buffer management circuits in the IC are cleared, making the buffer
612
+ empty. The BFEMPT interrupt status is established.
613
+ (Note) Set the SMEN bit low at the same time as this bit is set high.
614
+ (2) Setting this bit high when the sound map ADPCM playback is not being performed has no
615
+ effect whatsoever
616
+ bit 4: CLRBFWRDY (clear buffer write ready interrupt)
617
+ bit 3: CLRBFEMPT (clear buffer write empty interrupt)
618
+ bits 2 to 0: CLRINT#2 to 0 (clear interrupt #2 to 0)
619
+ bit 4 clears the corresponding interrupt status.
620
+ */
621
+ // clang-format on
502
622
bool ack = false ;
503
623
// cause ack
504
624
if (value == 0x07 ) {
@@ -534,11 +654,23 @@ class CDRomImpl final : public PCSX::CDRom {
534
654
PCSX::g_system->pause ();
535
655
} break ;
536
656
case 2 : {
537
- // Volume setting LR
538
- PCSX::g_system-> log (PCSX::LogClass::CDROM, " CD-Rom: w3:2 not available yet \n " ) ;
657
+ // ATV1 Left-to-Right
658
+ m_atv[ 1 ] = value ;
539
659
} break ;
540
660
case 3 : {
541
- // SPU settings latch
661
+ // clang-format off
662
+ /*
663
+ ADPCTL (ADPCM control) register
664
+ bit 5: CHNGATV (change ATV register)
665
+ The host sets this bit high after the changes of the ATV 3 to 0 registers have been completed. The
666
+ attenuator value in the IC is switched for the first time. There is no need for the host to set this bit
667
+ low. The bit used to set the ATV3 to 0 registers of the host and to synchronize the IC audio
668
+ playback.
669
+ bit 0: ADPMUTE (ADPCM mute)
670
+ Set high to mute the ADPCM sound for ADPCM decoding.
671
+ bits 7, 6, 4 to 1: Reserved
672
+ */
673
+ // clang-format on
542
674
PCSX::g_system->log (PCSX::LogClass::CDROM, " CD-Rom: w3:3 not available yet\n " );
543
675
} break ;
544
676
}
@@ -742,7 +874,7 @@ class CDRomImpl final : public PCSX::CDRom {
742
874
m_invalidLocL = false ;
743
875
m_speed = Speed::Simple;
744
876
m_status = Status::Idle;
745
- m_causeMask = 0x1f ;
877
+ m_interruptCauseMask = 0x1f ;
746
878
m_readingState = ReadingState::None;
747
879
memset (m_lastLocP, 0 , sizeof (m_lastLocP));
748
880
// Probably need to cancel other scheduled tasks here.
0 commit comments