Skip to content

Commit f3c0ecc

Browse files
committed
Adding CXD1199 datasheet information.
1 parent 68192a2 commit f3c0ecc

File tree

2 files changed

+174
-41
lines changed

2 files changed

+174
-41
lines changed

src/core/cdrom.cc

Lines changed: 171 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ namespace {
3838

3939
using namespace std::literals;
4040

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+
4144
class CDRomImpl final : public PCSX::CDRom {
4245
enum Commands {
4346
CdlSync = 0,
@@ -104,14 +107,14 @@ class CDRomImpl final : public PCSX::CDRom {
104107
m_seed = 9223521712174600777ull;
105108
m_dataFIFOIndex = 0;
106109
m_dataFIFOSize = 0;
107-
m_registerIndex = 0;
110+
m_registerAddress = 0;
108111
m_currentPosition.reset();
109112
m_seekPosition.reset();
110113
m_speed = Speed::Simple;
111114
m_speedChanged = false;
112115
m_status = Status::Idle;
113116
m_dataRequested = false;
114-
m_causeMask = 0x1f;
117+
m_interruptCauseMask = 0x1f;
115118
m_subheaderFilter = false;
116119
m_realtime = false;
117120
m_commandFifo.clear();
@@ -279,7 +282,7 @@ class CDRomImpl final : public PCSX::CDRom {
279282
void maybeTriggerIRQ(Cause cause, QueueElement &element) {
280283
uint8_t causeValue = static_cast<uint8_t>(cause);
281284
uint8_t bit = 1 << (causeValue - 1);
282-
if (m_causeMask & bit) {
285+
if (m_interruptCauseMask & bit) {
283286
element.setValue(cause);
284287
bool actuallyTriggering = false;
285288
if (maybeEnqueueResponse(element)) {
@@ -329,15 +332,49 @@ class CDRomImpl final : public PCSX::CDRom {
329332
}
330333

331334
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+
*/
338341
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;
341378
const bool debug = PCSX::g_emulator->settings.get<PCSX::Emulator::SettingDebugSettings>()
342379
.get<PCSX::Emulator::DebugSettings::LoggingHWCDROM>();
343380
if (debug) {
@@ -349,6 +386,7 @@ class CDRomImpl final : public PCSX::CDRom {
349386
}
350387

351388
uint8_t read1() override {
389+
// RESULT
352390
uint8_t ret = m_responseFifo[0].readPayloadByte();
353391
maybeScheduleNextCommand();
354392

@@ -362,6 +400,7 @@ class CDRomImpl final : public PCSX::CDRom {
362400
}
363401

364402
uint8_t read2() override {
403+
// RD DATA
365404
uint8_t ret = 0;
366405
if (!dataFIFOHasData()) {
367406
ret = 0;
@@ -379,35 +418,53 @@ class CDRomImpl final : public PCSX::CDRom {
379418
}
380419

381420
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+
382438
uint8_t ret = 0;
383-
switch (m_registerIndex & 1) {
439+
switch (m_registerAddress & 1) {
384440
case 0: {
385-
ret = m_causeMask | 0xe0;
441+
// HINT MSK (host interrupt mask)
442+
ret = m_interruptCauseMask;
386443
} break;
387444
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();
391447
} break;
392448
}
393449
const bool debug = PCSX::g_emulator->settings.get<PCSX::Emulator::SettingDebugSettings>()
394450
.get<PCSX::Emulator::DebugSettings::LoggingHWCDROM>();
395451
if (debug) {
396452
auto &regs = PCSX::g_emulator->m_cpu->m_regs;
397453
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);
399455
}
400-
return ret;
456+
return ret | 0xe0;
401457
}
402458

403459
void write0(uint8_t value) override {
460+
// ADDRESS
404461
const bool debug = PCSX::g_emulator->settings.get<PCSX::Emulator::SettingDebugSettings>()
405462
.get<PCSX::Emulator::DebugSettings::LoggingHWCDROM>();
406463
if (debug) {
407464
auto &regs = PCSX::g_emulator->m_cpu->m_regs;
408465
PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w0: %02x\n", regs.pc, regs.cycle, value);
409466
}
410-
m_registerIndex = value & 3;
467+
m_registerAddress = value & 3;
411468
}
412469

413470
void write1(uint8_t value) override {
@@ -416,10 +473,11 @@ class CDRomImpl final : public PCSX::CDRom {
416473
if (debug) {
417474
auto &regs = PCSX::g_emulator->m_cpu->m_regs;
418475
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);
420477
}
421-
switch (m_registerIndex) {
478+
switch (m_registerAddress) {
422479
case 0:
480+
// COMMAND
423481
m_commandFifo.value = value;
424482
if (!m_commandFifo.hasValue) {
425483
if (PCSX::g_emulator->settings.get<PCSX::Emulator::SettingDebugSettings>()
@@ -431,18 +489,35 @@ class CDRomImpl final : public PCSX::CDRom {
431489
m_commandFifo.hasValue = true;
432490
break;
433491
case 1: {
434-
// ??
492+
// WR DATA
435493
PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:1 not available yet\n");
436494
PCSX::g_system->pause();
437495
} break;
438496
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+
*/
440515
PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:2 not available yet\n");
441516
PCSX::g_system->pause();
442517
} break;
443518
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;
446521
} break;
447522
}
448523
}
@@ -453,22 +528,24 @@ class CDRomImpl final : public PCSX::CDRom {
453528
if (debug) {
454529
auto &regs = PCSX::g_emulator->m_cpu->m_regs;
455530
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);
457532
}
458-
switch (m_registerIndex) {
533+
switch (m_registerAddress) {
459534
case 0: {
535+
// PARAMETER
460536
m_commandFifo.pushPayloadData(value);
461537
} break;
462538
case 1: {
463-
m_causeMask = value;
539+
// HINT MSK (host interrupt mask)
540+
m_interruptCauseMask = value;
464541
} break;
465542
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;
468545
} break;
469546
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;
472549
} break;
473550
}
474551
}
@@ -479,11 +556,25 @@ class CDRomImpl final : public PCSX::CDRom {
479556
if (debug) {
480557
auto &regs = PCSX::g_emulator->m_cpu->m_regs;
481558
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);
483560
}
484-
switch (m_registerIndex) {
561+
switch (m_registerAddress) {
485562
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;
487578
if (value == 0) {
488579
m_dataRequested = false;
489580
m_dataFIFOSize = 0;
@@ -499,6 +590,35 @@ class CDRomImpl final : public PCSX::CDRom {
499590
PCSX::g_system->pause();
500591
} break;
501592
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
502622
bool ack = false;
503623
// cause ack
504624
if (value == 0x07) {
@@ -534,11 +654,23 @@ class CDRomImpl final : public PCSX::CDRom {
534654
PCSX::g_system->pause();
535655
} break;
536656
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;
539659
} break;
540660
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
542674
PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:3 not available yet\n");
543675
} break;
544676
}
@@ -742,7 +874,7 @@ class CDRomImpl final : public PCSX::CDRom {
742874
m_invalidLocL = false;
743875
m_speed = Speed::Simple;
744876
m_status = Status::Idle;
745-
m_causeMask = 0x1f;
877+
m_interruptCauseMask = 0x1f;
746878
m_readingState = ReadingState::None;
747879
memset(m_lastLocP, 0, sizeof(m_lastLocP));
748880
// Probably need to cancel other scheduled tasks here.

src/core/cdrom.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class CDRom {
113113
uint32_t m_dataFIFOIndex = 0;
114114
uint32_t m_dataFIFOSize = 0;
115115
uint32_t m_dataFIFOPending = 0;
116-
uint8_t m_registerIndex = 0;
116+
uint8_t m_registerAddress = 0;
117117
bool m_motorOn = false;
118118
bool m_speedChanged = false;
119119
bool m_invalidLocL = false;
@@ -139,7 +139,8 @@ class CDRom {
139139
} m_status = Status::Idle;
140140
enum class Speed : uint8_t { Simple, Double } m_speed;
141141
enum class ReadSpan : uint8_t { S2048, S2328, S2340 } m_readSpan;
142-
uint8_t m_causeMask = 0x1f;
142+
uint8_t m_interruptCauseMask = 0x1f;
143+
uint8_t m_atv[4] = {0};
143144

144145
enum class Cause : uint8_t {
145146
None = 0,

0 commit comments

Comments
 (0)