From 246ed238b55785a707a46bea0d130e95ec594079 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 5 Dec 2022 22:01:01 -0800 Subject: [PATCH 001/185] Starting fresh. --- src/core/cdrom.cc | 1533 +-------------------------------- src/core/cdrom.h | 88 +- src/core/r3000a.cc | 27 - src/core/r3000a.h | 6 - src/core/sstate.cc | 68 +- src/core/sstate.h | 78 +- src/gui/gui.cc | 15 +- src/gui/widgets/isobrowser.cc | 4 +- src/main/main.cc | 2 +- 9 files changed, 49 insertions(+), 1772 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index a255447a8..02cb26d8a 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -33,8 +33,7 @@ namespace { -class CDRomImpl : public PCSX::CDRom { - /* CD-ROM magic numbers */ +class CDRomImpl final : public PCSX::CDRom { enum Commands { CdlSync = 0, CdlGetStat = 1, @@ -69,1522 +68,22 @@ class CDRomImpl : public PCSX::CDRom { CdlReadToc = 30, }; - static const size_t cdCmdEnumCount = magic_enum::enum_count(); + static constexpr size_t c_cdCmdEnumCount = magic_enum::enum_count(); - static const inline uint8_t Test20[] = {0x98, 0x06, 0x10, 0xC3}; - static const inline uint8_t Test22[] = {0x66, 0x6F, 0x72, 0x20, 0x45, 0x75, 0x72, 0x6F}; - static const inline uint8_t Test23[] = {0x43, 0x58, 0x44, 0x32, 0x39, 0x34, 0x30, 0x51}; - static const unsigned irqReschedule = 0x100; + void reset() override {} - // m_stat: - enum { - NoIntr = 0, - DataReady = 1, - Complete = 2, - Acknowledge = 3, - DataEnd = 4, - DiskError = 5, - }; - - /* m_ctrl */ - enum { - BUSYSTS = 1 << 7, // 0x80 Command/parameter transmission busy (1=Busy) - DRQSTS = 1 << 6, // 0x40 Data fifo empty (0=Empty) - RSLRRDY = 1 << 5, // 0x20 Response fifo empty (0=Empty) - PRMWRDY = 1 << 4, // 0x10 Parameter fifo full (0=Full) - PRMEMPT = 1 << 3, // 0x08 Parameter fifo empty (1=Empty) - ADPBUSY = 1 << 2 // 0x04 XA-ADPCM fifo empty (0=Empty) - }; - - /* Modes flags */ - enum { - MODE_SPEED = 1 << 7, // 0x80 - MODE_STRSND = 1 << 6, // 0x40 ADPCM on/off - MODE_SIZE_2340 = 1 << 5, // 0x20 - MODE_SIZE_2328 = 1 << 4, // 0x10 - MODE_SIZE_2048 = 0 << 4, // 0x00 - MODE_SF = 1 << 3, // 0x08 channel on/off - MODE_REPORT = 1 << 2, // 0x04 - MODE_AUTOPAUSE = 1 << 1, // 0x02 - MODE_CDDA = 1 << 0, // 0x01 - }; - - /* Status flags */ - enum { - STATUS_PLAY = 1 << 7, // 0x80 - STATUS_SEEK = 1 << 6, // 0x40 - STATUS_READ = 1 << 5, // 0x20 - STATUS_SHELLOPEN = 1 << 4, // 0x10 - STATUS_UNKNOWN3 = 1 << 3, // 0x08 - STATUS_UNKNOWN2 = 1 << 2, // 0x04 - STATUS_ROTATING = 1 << 1, // 0x02 - STATUS_ERROR = 1 << 0, // 0x01 - }; - - /* Errors */ - enum { - ERROR_NOTREADY = 1 << 7, // 0x80 - ERROR_INVALIDCMD = 1 << 6, // 0x40 - ERROR_INVALIDARG = 1 << 5, // 0x20 - }; - -// 1x = 75 sectors per second -// PCSX::g_emulator->m_psxClockSpeed = 1 sec in the ps -// so (PCSX::g_emulator->m_psxClockSpeed / 75) = m_cdr read time (linuzappz) -#define cdReadTime (PCSX::g_emulator->m_psxClockSpeed / 75) - - enum drive_state { - DRIVESTATE_STANDBY = 0, - DRIVESTATE_LID_OPEN, - DRIVESTATE_RESCAN_CD, - DRIVESTATE_PREPARE_CD, - DRIVESTATE_STOPPED, - }; - - // for m_seeked - enum seeked_state { - SEEK_PENDING = 0, - SEEK_DONE = 1, - }; - - struct PCSX::CdrStat cdr_stat; - - static const uint32_t H_SPUirqAddr = 0x1f801da4; - static const uint32_t H_SPUctrl = 0x1f801daa; - - // interrupt - static inline void scheduleCDIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDR, eCycle); - } - - // readInterrupt - static inline void scheduleCDReadIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDREAD, eCycle); - } - - // decodedBufferInterrupt - static inline void scheduleDecodeBufferIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRDBUF, eCycle); - } - - // lidSeekInterrupt - static inline void scheduleCDLidIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRLID, eCycle); - } - - // playInterrupt - static inline void scheduleCDPlayIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRPLAY, eCycle); - } - - static inline void scheduleCDDMAIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRDMA, eCycle); - } - - inline void StopReading() { - if (m_reading) { - m_reading = 0; - PCSX::g_emulator->m_cpu->m_regs.interrupt &= ~(1 << PCSX::PSXINT_CDREAD); - } - m_statP &= ~(STATUS_READ | STATUS_SEEK); - } - - inline void StopCdda() { - if (m_play) { - m_statP &= ~STATUS_PLAY; - m_play = false; - m_fastForward = 0; - m_fastBackward = 0; - // PCSX::g_emulator->m_spu->registerCallback(SPUirq); - } - } - - inline void SetResultSize(uint8_t size) { - m_resultP = 0; - m_resultC = size; - m_resultReady = 1; - } - - inline void setIrq(void) { - if (m_stat & m_reg2) psxHu32ref(0x1070) |= SWAP_LE32((uint32_t)0x4); - } - - void adjustTransferIndex(void) { - size_t bufSize = 0; - - switch (m_mode & (MODE_SIZE_2340 | MODE_SIZE_2328)) { - case MODE_SIZE_2340: - bufSize = 2340; - break; - case MODE_SIZE_2328: - bufSize = 12 + 2328; - break; - case MODE_SIZE_2048: - default: - bufSize = 12 + 2048; - break; - } - - if (m_transferIndex >= bufSize) m_transferIndex -= bufSize; - - // FIFO empty - if (m_transferIndex == 0) { - m_ctrl &= ~DRQSTS; // Data fifo empty - m_read = 0; - } - } - - // FIXME: do this in SPU instead - void decodedBufferInterrupt() final { -#if 0 - return; -#endif - - // check dbuf IRQ still active - if (!m_play) return; - if ((PCSX::g_emulator->m_spu->readRegister(H_SPUctrl) & 0x40) == 0) return; - if ((PCSX::g_emulator->m_spu->readRegister(H_SPUirqAddr) * 8) >= 0x800) return; - - // turn off plugin SPU IRQ decoded buffer handling - // PCSX::g_emulator->m_spu->registerCallback(0); - - /* - Vib Ribbon - - 000-3FF = left CDDA - 400-7FF = right CDDA - - Assume IRQ every wrap - */ - - // signal CDDA data ready - psxHu32ref(0x1070) |= SWAP_LE32((uint32_t)0x200); - - // time for next full buffer - // scheduleDecodeBufferIRQ( PCSX::g_emulator->m_psxClockSpeed / 44100 * 0x200 ); - scheduleDecodeBufferIRQ(PCSX::g_emulator->m_psxClockSpeed / 44100 * 0x100); - } - - void getStatus(PCSX::CdrStat *stat) { - if (isLidOpened()) { - stat->Status = 0x10; - } else { - stat->Status = 0; - } - if (m_play) { - stat->Type = 0x02; - stat->Status |= 0x80; - } else { - // BIOS - boot ID (CD type) - stat->Type = magic_enum::enum_integer(m_iso->getTrackType(1)); - } - - // relative -> absolute time - stat->Time = m_setSectorPlay; - } - - // timing used in this function was taken from tests on real hardware - // (yes it's slow, but you probably don't want to modify it) - void lidSeekInterrupt() final { - switch (m_driveState) { - default: - case DRIVESTATE_STANDBY: - m_statP &= ~STATUS_SEEK; - - getStatus(&cdr_stat); - - if (cdr_stat.Status & STATUS_SHELLOPEN) { - StopCdda(); - m_driveState = DRIVESTATE_LID_OPEN; - scheduleCDLidIRQ(8 * irqReschedule); - } - break; - - case DRIVESTATE_LID_OPEN: - getStatus(&cdr_stat); - - // 02, 12, 10 - if (!(m_statP & STATUS_SHELLOPEN)) { - StopReading(); - m_statP |= STATUS_SHELLOPEN; - - // could generate error irq here, but real hardware - // only sometimes does that - // (not done when lots of commands are sent?) - - scheduleCDLidIRQ(cdReadTime * 30); - break; - } else if (m_statP & STATUS_ROTATING) { - m_statP &= ~STATUS_ROTATING; - } else if (!(cdr_stat.Status & STATUS_SHELLOPEN)) { - // closed now - check(); - - // m_statP STATUS_SHELLOPEN is "sticky" - // and is only cleared by CdlGetStat - - m_driveState = DRIVESTATE_RESCAN_CD; - scheduleCDLidIRQ(cdReadTime * 105); - break; - } - - // recheck for close - scheduleCDLidIRQ(cdReadTime * 3); - break; - - case DRIVESTATE_RESCAN_CD: - m_statP |= STATUS_ROTATING; - m_driveState = DRIVESTATE_PREPARE_CD; - - // this is very long on real hardware, over 6 seconds - // make it a bit faster here... - scheduleCDLidIRQ(cdReadTime * 150); - break; - - case DRIVESTATE_PREPARE_CD: - m_statP |= STATUS_SEEK; - - m_driveState = DRIVESTATE_STANDBY; - scheduleCDLidIRQ(cdReadTime * 26); - break; - } - } - - void Find_CurTrack(const MSF time) { - int current, sect; - - current = time.toLBA(); - - for (m_curTrack = 1; m_curTrack < m_iso->getTN(); m_curTrack++) { - sect = static_cast(m_iso->getTD(m_curTrack + 1).toLBA()); - if (sect - current >= 150) break; - } - CDROM_LOG("Find_CurTrack *** %02d %02d\n", m_curTrack, current); - } - - void generate_subq(const MSF time) { - unsigned int this_s, start_s, next_s, pregap; - int relative_s; - - MSF start = m_iso->getTD(m_curTrack); - MSF next; - if (m_curTrack + 1 <= m_iso->getTN()) { - pregap = 150; - next = m_iso->getTD(m_curTrack + 1); - } else { - // last track - cd size - pregap = 0; - next = m_setSectorEnd; - } - - this_s = time.toLBA(); - start_s = start.toLBA(); - next_s = next.toLBA(); - - m_trackChanged = false; - - if (next_s - this_s < pregap) { - m_trackChanged = true; - m_curTrack++; - start_s = next_s; - } - - m_subq.index = 1; - - relative_s = this_s - start_s; - if (relative_s < 0) { - m_subq.index = 0; - relative_s = -relative_s; - } - m_subq.track = PCSX::IEC60908b::itob(m_curTrack); - MSF(relative_s).toBCD(m_subq.relative); - time.toBCD(m_subq.absolute); - } - - void readTrack(MSF time) { - if (m_prev == time) return; - - CDROM_LOG("ReadTrack *** %02i:%02i:%02i\n", time.m, time.s, time.f); - - m_prev.reset(); - if (m_iso->getTrackType(m_curTrack) == PCSX::CDRIso::TrackType::CDDA) { - m_suceeded = false; - } else { - m_suceeded = m_iso->readTrack(time); - if (m_suceeded) m_prev = time; - } - - const PCSX::IEC60908b::Sub *sub = m_iso->getBufferSub(); - if (sub && m_curTrack == 1) { - uint16_t calcCRC = PCSX::IEC60908b::subqCRC(sub->Q); - uint16_t actualCRC = sub->CRC[0]; - actualCRC <<= 8; - actualCRC |= sub->CRC[1]; - if (calcCRC == actualCRC) { - m_subq.track = sub->TrackNumber; - m_subq.index = sub->IndexNumber; - memcpy(m_subq.relative, sub->RelativeAddress, 3); - memcpy(m_subq.absolute, sub->AbsoluteAddress, 3); - } else { - CDROM_IO_LOG("subq bad crc @%02i:%02i:%02i\n", time.m, time.s, time.f); - } - } else { - generate_subq(time); - } - - CDROM_LOG(" -> %02x,%02x %02x:%02x:%02x %02x:%02x:%02x\n", m_subq.track, m_subq.index, m_subq.relative[0], - m_subq.relative[1], m_subq.relative[2], m_subq.absolute[0], m_subq.absolute[1], m_subq.absolute[2]); - } - - void AddIrqQueue(unsigned short irq, unsigned long ecycle) { - if (m_irq != 0) { - if (irq == m_irq || irq + 0x100 == m_irq) { - m_irqRepeated = 1; - scheduleCDIRQ(ecycle); - return; - } - CDROM_IO_LOG("cdr: override cmd %02x -> %02x\n", m_irq, irq); - } - - m_irq = irq; - m_eCycle = ecycle; - - scheduleCDIRQ(ecycle); - } - - void cdrPlayInterrupt_Autopause() { - if ((m_mode & MODE_AUTOPAUSE) && m_trackChanged) { - CDROM_LOG("CDDA STOP\n"); - // Magic the Gathering - // - looping territory cdda - - // ...? - // m_resultReady = 1; - // m_stat = DataReady; - m_stat = DataEnd; - setIrq(); - - StopCdda(); - } else if (m_mode & MODE_REPORT) { - m_result[0] = m_statP; - m_result[1] = m_subq.track; - m_result[2] = m_subq.index; - unsigned abs_lev_chselect = m_subq.absolute[1] & 0x01; - uint32_t abs_lev_max = 0; - int16_t *data = reinterpret_cast(m_transfer); - for (unsigned i = 0; i < 588; i++) { - abs_lev_max = std::max(abs_lev_max, std::abs(data[i * 2 + abs_lev_chselect])); - } - abs_lev_max = std::min(abs_lev_max, 32767U); - abs_lev_max |= abs_lev_chselect << 15; - - if (m_subq.absolute[2] & 0x10) { - m_result[3] = m_subq.relative[0]; - m_result[4] = m_subq.relative[1] | 0x80; - m_result[5] = m_subq.relative[2]; - } else { - m_result[3] = m_subq.absolute[0]; - m_result[4] = m_subq.absolute[1]; - m_result[5] = m_subq.absolute[2]; - } - - m_result[6] = abs_lev_max & 0xff; - m_result[7] = abs_lev_max >> 8; - - // Rayman: Logo freeze (resultready + dataready) - m_resultReady = 1; - m_stat = DataReady; - - SetResultSize(8); - setIrq(); - } - } - - // also handles seek - void playInterrupt() final { - if (m_seeked == SEEK_PENDING) { - if (m_stat) { - scheduleCDPlayIRQ(irqReschedule); - return; - } - SetResultSize(1); - m_statP |= STATUS_ROTATING; - m_statP &= ~STATUS_SEEK; - m_result[0] = m_statP; - m_seeked = SEEK_DONE; - if (m_irq == 0) { - m_stat = Complete; - m_suceeded = true; - setIrq(); - } - - if (m_setlocPending) { - m_setSectorPlay = m_setSector; - m_setlocPending = 0; - m_locationChanged = true; - } - Find_CurTrack(m_setSectorPlay); - readTrack(m_setSectorPlay); - m_trackChanged = false; - } - - if (!m_play) return; - CDROM_LOG("CDDA - %02d:%02d:%02d\n", m_setSectorPlay.m, m_setSectorPlay.s, m_setSectorPlay.f); - if (m_setSectorPlay == m_setSectorEnd) { - StopCdda(); - m_trackChanged = true; - } - - m_iso->readCDDA(m_setSectorPlay, m_transfer); - if (!m_irq && !m_stat && (m_mode & (MODE_AUTOPAUSE | MODE_REPORT))) cdrPlayInterrupt_Autopause(); - - if (!m_play) return; - - if (!m_muted) { - attenuate((int16_t *)m_transfer, PCSX::IEC60908b::FRAMESIZE_RAW / 4, 1); - PCSX::g_emulator->m_spu->playCDDAchannel((short *)m_transfer, PCSX::IEC60908b::FRAMESIZE_RAW); - } - - m_setSectorPlay++; - - if (m_locationChanged) { - scheduleCDPlayIRQ(cdReadTime * 30); - m_locationChanged = false; - } else { - scheduleCDPlayIRQ(cdReadTime); - } - - // update for CdlGetlocP/autopause - generate_subq(m_setSectorPlay); - } - - void interrupt() final { - uint16_t irq = m_irq; - int no_busy_error = 0; - int start_rotating = 0; - int error = 0; - int delay; - - // Reschedule IRQ - if (m_stat) { - scheduleCDIRQ(irqReschedule); - return; - } - - m_ctrl &= ~BUSYSTS; // Command/parameter transmission not busy - - // default response - SetResultSize(1); - m_result[0] = m_statP; - m_stat = Acknowledge; - - if (m_irqRepeated) { - m_irqRepeated = 0; - if (m_eCycle > PCSX::g_emulator->m_cpu->m_regs.cycle) { - scheduleCDIRQ(m_eCycle); - goto finish; - } - } - - m_irq = 0; - CDROM_IO_LOG("CDRINT %x %x %x %x\n", m_seeked, m_stat, irq, m_irqRepeated); - if ((irq & 0x100) && PCSX ::g_emulator->settings.get() - .get()) { - logCDROM(irq); - } - - switch (irq) { - case CdlGetStat: - if (m_driveState != DRIVESTATE_LID_OPEN) m_statP &= ~STATUS_SHELLOPEN; - no_busy_error = 1; - break; - - case CdlSetloc: - break; - - do_CdlPlay: - case CdlPlay: - StopCdda(); - if (m_seeked == SEEK_PENDING) { - // XXX: wrong, should seek instead.. - m_seeked = SEEK_DONE; - } - if (m_setlocPending) { - m_setSectorPlay = m_setSector; - m_setlocPending = 0; - m_locationChanged = true; - } - - // BIOS CD Player - // - Pause player, hit Track 01/02/../xx (Setloc issued!!) - - if (m_paramC == 0 || m_param[0] == 0) { - CDROM_LOG("PLAY Resume @ %d:%d:%d\n", m_setSectorPlay.m, m_setSectorPlay.s, m_setSectorPlay.f); - } else { - int track = PCSX::IEC60908b::btoi(m_param[0]); - if (track <= m_iso->getTN()) m_curTrack = track; - CDROM_LOG("PLAY track %d\n", m_curTrack); - m_setSectorPlay = m_iso->getTD(m_curTrack); - } - - /* - Rayman: detect track changes - - fixes logo freeze - - Twisted Metal 2: skip PREGAP + starting accurate SubQ - - plays tracks without retry play - - Wild 9: skip PREGAP + starting accurate SubQ - - plays tracks without retry play - */ - Find_CurTrack(m_setSectorPlay); - readTrack(m_setSectorPlay); - m_trackChanged = false; - - // Vib Ribbon: gameplay checks flag - m_statP &= ~STATUS_SEEK; - m_result[0] = m_statP; - - m_statP |= STATUS_PLAY; - - // BIOS player - set flag again - m_play = true; - - scheduleCDPlayIRQ(cdReadTime); - start_rotating = 1; - break; - - case CdlForward: - // TODO: error 80 if stopped - m_stat = Complete; - m_suceeded = true; - - // GameShark CD Player: Calls 2x + Play 2x - if (m_fastForward == 0) { - m_fastForward = 2; - } else { - m_fastForward++; - } - - m_fastBackward = 0; - break; - - case CdlBackward: - m_stat = Complete; - m_suceeded = true; - - // GameShark CD Player: Calls 2x + Play 2x - if (m_fastBackward == 0) { - m_fastBackward = 2; - } else { - m_fastBackward++; - } - - m_fastForward = 0; - break; - - case CdlStandby: - if (m_driveState != DRIVESTATE_STOPPED) { - error = ERROR_INVALIDARG; - goto set_error; - } - AddIrqQueue(CdlStandby + 0x100, cdReadTime * 125 / 2); - start_rotating = 1; - break; - - case CdlStandby + 0x100: - m_stat = Complete; - m_suceeded = true; - break; - - case CdlStop: - if (m_play) { - // grab time for current track - m_setSectorPlay = m_iso->getTD(m_curTrack); - } - - StopCdda(); - StopReading(); - - delay = 0x800; - if (m_driveState == DRIVESTATE_STANDBY) delay = cdReadTime * 30 / 2; - - m_driveState = DRIVESTATE_STOPPED; - AddIrqQueue(CdlStop + 0x100, delay); - break; - - case CdlStop + 0x100: - m_statP &= ~STATUS_ROTATING; - m_result[0] = m_statP; - m_stat = Complete; - m_suceeded = true; - break; - - case CdlPause: - /* - Gundam Battle Assault 2: much slower (*) - - Fixes boot, gameplay - - Hokuto no Ken 2: slower - - Fixes intro + subtitles - - InuYasha - Feudal Fairy Tale: slower - - Fixes battles - */ - /* - * Gameblabla - - * The timings are based on hardware tests and were taken from Duckstation. - * A couple of notes : - * Gundam Battle Assault 2 in PAL mode (this includes the PAL release) needs a high enough delay - * if not, the game will either crash after the FMV intro or upon starting a new game. - * - */ - if (m_driveState == DRIVESTATE_STANDBY) { - /* Gameblabla - - * Dead or Alive needs this condition and a shorter delay otherwise : if you pause ingame, music - * will not resume. */ - delay = 7000; - } else { - delay = (((m_mode & MODE_SPEED) ? 2 : 1) * (1000000)); - scheduleCDPlayIRQ((m_mode & MODE_SPEED) ? cdReadTime / 2 : cdReadTime); - } - AddIrqQueue(CdlPause + 0x100, delay); - m_ctrl |= BUSYSTS; // Command/parameter transmission busy - break; - - case CdlPause + 0x100: - m_statP &= ~STATUS_READ; - m_result[0] = m_statP; - m_stat = Complete; - m_suceeded = true; - break; - - case CdlReset: - m_muted = false; - m_mode = 0x20; /* This fixes This is Football 2, Pooh's Party lockups */ - AddIrqQueue(CdlReset + 0x100, 4100000); // 4100000 is from Mednafen - no_busy_error = 1; - start_rotating = 1; - break; - - case CdlReset + 0x100: - m_stat = Complete; - m_suceeded = true; - break; - - case CdlMute: - m_muted = true; - break; - - case CdlDemute: - m_muted = false; - break; - - case CdlSetfilter: - m_file = m_param[0]; - m_channel = m_param[1]; - break; - - case CdlSetmode: - no_busy_error = 1; - break; - - case CdlGetparam: - SetResultSize(5); - m_result[1] = m_mode; - m_result[2] = 0; - m_result[3] = m_file; - m_result[4] = m_channel; - no_busy_error = 1; - break; - - case CdlGetlocL: - SetResultSize(8); - memcpy(m_result, m_transfer, 8); - break; - - case CdlGetlocP: - SetResultSize(8); - memcpy(&m_result, &m_subq, 8); - - if (!m_play && m_iso->CheckSBI(m_result + 5)) memset(m_result + 2, 0, 6); - if (!m_play && !m_reading) m_result[1] = 0; // HACK? - break; - - case CdlReadT: // SetSession? - // really long - AddIrqQueue(CdlReadT + 0x100, cdReadTime * 290 / 4); - start_rotating = 1; - break; - - case CdlReadT + 0x100: - m_stat = Complete; - m_suceeded = true; - break; - - case CdlGetTN: - if (m_iso->failed()) { - m_stat = DiskError; - m_result[0] |= STATUS_ERROR; - } else { - SetResultSize(3); - m_stat = Acknowledge; - m_result[1] = 1; - m_result[2] = PCSX::IEC60908b::itob(m_iso->getTN()); - } - break; - - case CdlGetTD: { - if (m_iso->failed()) { - m_stat = DiskError; - m_result[0] |= STATUS_ERROR; - } else { - m_track = PCSX::IEC60908b::btoi(m_param[0]); - SetResultSize(4); - m_stat = Acknowledge; - MSF td = m_iso->getTD(m_track); - m_result[0] = m_statP; - m_result[1] = PCSX::IEC60908b::itob(td.m); - m_result[2] = PCSX::IEC60908b::itob(td.s); - } - break; - } - - case CdlSeekL: - case CdlSeekP: - StopCdda(); - StopReading(); - m_statP |= STATUS_SEEK; - - /* - Crusaders of Might and Magic = 0.5x-4x - - fix cutscene speech start - - Eggs of Steel = 2x-? - - fix new game - - Medievil = ?-4x - - fix cutscene speech - - Rockman X5 = 0.5-4x - - fix capcom logo - */ - scheduleCDPlayIRQ(m_seeked == SEEK_DONE ? 0x800 : cdReadTime * 4); - m_seeked = SEEK_PENDING; - start_rotating = 1; - break; - - case CdlTest: - switch (m_param[0]) { - case 0x20: // System Controller ROM Version - SetResultSize(4); - memcpy(m_result, Test20, 4); - break; - case 0x22: - SetResultSize(8); - memcpy(m_result, Test22, 4); - break; - case 0x23: - case 0x24: - SetResultSize(8); - memcpy(m_result, Test23, 4); - break; - } - no_busy_error = 1; - break; - - case CdlID: - AddIrqQueue(CdlID + 0x100, 20480); - break; - - case CdlID + 0x100: - SetResultSize(8); - - if (m_iso->failed()) { - m_result[0] = 0x08; - m_result[1] = 0x40; - memset((char *)&m_result[2], 0, 6); - m_stat = DiskError; - break; - } - - m_result[0] = m_statP; - m_result[1] = 0; - m_result[2] = 0; - m_result[3] = 0; - - // 0x10 - audio | 0x40 - disk missing | 0x80 - unlicensed - getStatus(&cdr_stat); - if (cdr_stat.Type == 0 || cdr_stat.Type == 0xff) { - m_result[1] = 0xc0; - } else { - // Audio, unlicensed - if (cdr_stat.Type == 2) m_result[1] |= (0x10 | 0x80); - } - m_result[0] |= (m_result[1] >> 4) & 0x08; - - strncpy((char *)&m_result[4], "PCSX", 4); - m_stat = Complete; - m_suceeded = true; - break; - - case CdlInit: - // yes, it really sets STATUS_SHELLOPEN - m_statP |= STATUS_SHELLOPEN; - m_driveState = DRIVESTATE_RESCAN_CD; - scheduleCDLidIRQ(20480); - no_busy_error = 1; - start_rotating = 1; - break; - - case CdlGetQ: - // TODO? - CDROM_LOG("got CdlGetQ\n"); - break; - - case CdlReadToc: - AddIrqQueue(CdlReadToc + 0x100, cdReadTime * 180 / 4); - no_busy_error = 1; - start_rotating = 1; - break; - - case CdlReadToc + 0x100: - m_stat = Complete; - m_suceeded = true; - no_busy_error = 1; - break; - - case CdlReadN: - case CdlReadS: - if (m_setlocPending) { - m_setSectorPlay = m_setSector; - m_setlocPending = 0; - m_locationChanged = true; - } - Find_CurTrack(m_setSectorPlay); - - if ((m_mode & MODE_CDDA) && m_curTrack > 1) { - // Read* acts as play for cdda tracks in cdda mode - goto do_CdlPlay; - } - - m_reading = 1; - m_firstSector = 1; - - // Fighting Force 2 - update m_subq time immediately - // - fixes new game - readTrack(m_setSectorPlay); - - // Crusaders of Might and Magic - update getlocl now - // - fixes cutscene speech - { - uint8_t *buf = m_iso->getBuffer(); - if (buf != NULL) memcpy(m_transfer, buf, 8); - } - - /* - Duke Nukem: Land of the Babes - seek then delay read for one frame - - fixes cutscenes - C-12 - Final Resistance - doesn't like seek - */ - - // It LOOKS like this logic is wrong, therefore disabling it with `&& false` for now. - // - // For "PoPoLoCrois Monogatari II", the game logic will soft lock and will never issue GetLocP to detect - // the end of its XA streams, as it seems to assume ReadS will not return a status byte with the SEEK - // flag set. I think the reasonning is that since it's invalid to call GetLocP while seeking, the game - // tries to protect itself against errors by preventing from issuing a GetLocP while it knows the - // last status was "seek". But this makes the logic just softlock as it'll never get a notification - // about the fact the drive is done seeking and the read actually started. - // - // In other words, this state machine here is probably wrong in assuming the response to ReadS/ReadN is - // done right away. It's rather when it's done seeking, and the read has actually started. This probably - // requires a bit more work to make sure seek delays are processed properly. - // - // Checked with a few games, this seems to work fine. - if ((m_seeked != SEEK_DONE) && false) { - m_statP |= STATUS_SEEK; - m_statP &= ~STATUS_READ; - - // Crusaders of Might and Magic - use short time - // - fix cutscene speech (startup) - - // ??? - use more accurate seek time later - scheduleCDReadIRQ((m_mode & 0x80) ? (cdReadTime) : cdReadTime * 2); - } else { - m_statP |= STATUS_READ; - m_statP &= ~STATUS_SEEK; - - scheduleCDReadIRQ((m_mode & 0x80) ? (cdReadTime) : cdReadTime * 2); - } - - m_result[0] = m_statP; - start_rotating = 1; - break; - case CdlSync: - default: - CDROM_LOG("Invalid command: %02x\n", irq); - error = ERROR_INVALIDCMD; - - set_error: - SetResultSize(2); - m_result[0] = m_statP | STATUS_ERROR; - m_result[1] = error; - m_stat = DiskError; - break; - } - - if (m_driveState == DRIVESTATE_STOPPED && start_rotating) { - m_driveState = DRIVESTATE_STANDBY; - m_statP |= STATUS_ROTATING; - } - - if (!no_busy_error) { - switch (m_driveState) { - case DRIVESTATE_LID_OPEN: - case DRIVESTATE_RESCAN_CD: - case DRIVESTATE_PREPARE_CD: - SetResultSize(2); - m_result[0] = m_statP | STATUS_ERROR; - m_result[1] = ERROR_NOTREADY; - m_stat = DiskError; - break; - } - } - - finish: - setIrq(); - m_paramC = 0; - - { - CDROM_IO_LOG("CDR IRQ %d cmd %02x stat %02x: ", !!(m_stat & m_reg2), irq, m_stat); - for (int i = 0; i < m_resultC; i++) CDROM_IO_LOG("%02x ", m_result[i]); - CDROM_IO_LOG("\n"); - } - } - - static constexpr inline int ssat32_to_16(int v) { - if (v < -32768) { - v = -32768; - } else if (v > 32767) { - v = 32767; - } - return v; - } - - void attenuate(int16_t *buf, int samples, int stereo) final { - int i, l, r; - int ll = m_attenuatorLeftToLeft; - int lr = m_attenuatorLeftToRight; - int rl = m_attenuatorRightToLeft; - int rr = m_attenuatorRightToRight; - - if (lr == 0 && rl == 0 && 0x78 <= ll && ll <= 0x88 && 0x78 <= rr && rr <= 0x88) return; - - if (!stereo && ll == 0x40 && lr == 0x40 && rl == 0x40 && rr == 0x40) return; - - if (stereo) { - for (i = 0; i < samples; i++) { - l = buf[i * 2]; - r = buf[i * 2 + 1]; - l = (l * ll + r * rl) >> 7; - r = (r * rr + l * lr) >> 7; - buf[i * 2] = ssat32_to_16(l); - buf[i * 2 + 1] = ssat32_to_16(r); - } - } else { - for (i = 0; i < samples; i++) { - l = buf[i]; - l = l * (ll + rl) >> 7; - buf[i] = ssat32_to_16(l); - } - } - } - - void readInterrupt() final { - uint8_t *buf; - - if (!m_reading) return; - - if (m_irq || m_stat) { - scheduleCDReadIRQ(irqReschedule); - return; - } - - if ((psxHu32ref(0x1070) & psxHu32ref(0x1074) & SWAP_LE32((uint32_t)0x4)) && !m_readRescheduled) { - // HACK: with PCSX::Emulator::BIAS 2, emulated CPU is often slower than real thing, - // game may be unfinished with prev data read, so reschedule - // (Brave Fencer Musashi) - scheduleCDReadIRQ(cdReadTime / 2); - m_readRescheduled = 1; - return; - } - - SetResultSize(1); - m_statP |= STATUS_READ | STATUS_ROTATING; - m_statP &= ~STATUS_SEEK; - m_result[0] = m_statP; - m_seeked = SEEK_DONE; - - readTrack(m_setSectorPlay); - - buf = m_iso->getBuffer(); - if (buf == NULL) m_suceeded = false; - - if (!m_suceeded) { - CDROM_LOG("readInterrupt() Log: err\n"); - memset(m_transfer, 0, PCSX::IEC60908b::DATA_SIZE); - m_stat = DiskError; - m_result[0] |= STATUS_ERROR; - setIrq(); - return; - } - - memcpy(m_transfer, buf, PCSX::IEC60908b::DATA_SIZE); - m_ctrl |= DRQSTS; // Data fifo not empty - - CDROM_LOG("readInterrupt() Log: cdr.m_transfer %x:%x:%x\n", m_transfer[0], m_transfer[1], m_transfer[2]); - - if ((!m_muted) && (m_mode & MODE_STRSND) && (PCSX::g_emulator->settings.get()) && - (m_firstSector != -1)) { // CD-XA - // Firemen 2: Multi-XA files - briefings, cutscenes - if (m_firstSector == 1 && (m_mode & MODE_SF) == 0) { - m_file = m_transfer[4 + 0]; - m_channel = m_transfer[4 + 1]; - } - - /* Gameblabla - Ignore sectors with channel 255. - * This fixes the missing sound in Blue's Clues : Blue's Big Musical. - * (Taxi 2 is also said to be affected by the same issue) - * */ - if ((m_transfer[4 + 2] & 0x4) && (m_transfer[4 + 1] == m_channel) && (m_transfer[4 + 0] == m_file) && - m_channel != 255) { - int ret = xa_decode_sector(&m_xa, m_transfer + 4, m_firstSector); - if (!ret) { - attenuate(m_xa.pcm, m_xa.nsamples, m_xa.stereo); - PCSX::g_emulator->m_spu->playADPCMchannel(&m_xa); - m_firstSector = 0; - } else { - m_firstSector = -1; - } - } - } - - m_setSectorPlay++; - m_read = 0; - m_readRescheduled = 0; + void interrupt() override {} + void dmaInterrupt() override {} + uint8_t read0() override { return 0; } + uint8_t read1() override { return 0; } + uint8_t read2() override { return 0; } + uint8_t read3() override { return 0; } + void write0(uint8_t rt) override {} + void write1(uint8_t rt) override {} + void write2(uint8_t rt) override {} + void write3(uint8_t rt) override {} - uint32_t delay = (m_mode & MODE_SPEED) ? (cdReadTime / 2) : cdReadTime; - if (m_locationChanged) { - scheduleCDReadIRQ(delay * 30); - m_locationChanged = false; - } else { - scheduleCDReadIRQ(delay); - } - - /* - Croc 2: $40 - only FORM1 (*) - Judge Dredd: $C8 - only FORM1 (*) - Sim Theme Park - no adpcm at all (zero) - */ - - if (!(m_mode & MODE_STRSND) || !(m_transfer[4 + 2] & 0x4)) { - m_stat = DataReady; - setIrq(); - } - - // update for CdlGetlocP - readTrack(m_setSectorPlay); - } - - /* - read0: - 03 - bit 0,1 - mode - 04 - bit 2 - xa-adpcm fifo occupied - 08 - bit 3 - parameter fifo empty - 10 - bit 4 - parameter fifo safe to push to - 20 - bit 5 - 1 result ready - 40 - bit 6 - 1 dma ready - 80 - bit 7 - 1 command being processed - */ - - uint8_t read0(void) final { - if (m_resultReady) { - m_ctrl |= RSLRRDY; // Response fifo not empty - } else { - m_ctrl &= ~RSLRRDY; // Response fifo empty - } - - m_ctrl |= (PRMEMPT | PRMWRDY); // Parameter fifo empty, parameter not fifo full - - CDROM_IO_LOG("cdr r0: %02x\n", m_ctrl); - return psxHu8(0x1800) = m_ctrl; - } - - void write0(uint8_t rt) final { - CDROM_IO_LOG("cdr w0: %02x\n", rt); - m_ctrl = (rt & 3) | (m_ctrl & ~3); - } - - uint8_t read1(void) final { - if ((m_resultP & 0xf) < m_resultC) { - psxHu8(0x1801) = m_result[m_resultP & 0xf]; - } else { - psxHu8(0x1801) = 0; - } - m_resultP++; - if (m_resultP == m_resultC) m_resultReady = 0; - CDROM_IO_LOG("cdr r1: %02x\n", psxHu8(0x1801)); - return psxHu8(0x1801); - } - - void write1(uint8_t rt) final { - MSF set_loc; - int i; - CDROM_IO_LOG("cdr w1: %02x\n", rt); - switch (m_ctrl & 3) { - case 0: - break; - case 3: - m_attenuatorRightToRightT = rt; - return; - default: - return; - } - - m_cmd = rt; - if (PCSX::g_emulator->settings.get() - .get()) { - logCDROM(rt); - } - - if constexpr (PCSX::CDROM_IO_LOGGER::c_enabled) { - std::string args; - if (m_paramC) { - args = fmt::format(" Param[{}] = {{", m_paramC); - for (i = 0; i < m_paramC; i++) args += fmt::format(" {:02x},", m_param[i]); - args += "}"; - } - - if (rt > cdCmdEnumCount) { - CDROM_IO_LOG("CD1 write: %x (CdlUnknown) %s\n", rt, args); - } else { - CDROM_IO_LOG("CD1 write: %x (%s) %s\n", rt, magic_enum::enum_names()[rt], args); - } - } - - m_resultReady = 0; - m_ctrl |= BUSYSTS; // Command/parameter transmission busy - // m_stat = NoIntr; - AddIrqQueue(m_cmd, 0x800); - - switch (m_cmd) { - case CdlSetloc: - CDROM_LOG("CDROM setloc command (%02x, %02x, %02x)\n", m_param[0], m_param[1], m_param[2]); - // MM must be BCD, SS must be BCD and <0x60, FF must be BCD and <0x75 - if (((m_param[0] & 0x0f) > 0x09) || (m_param[0] > 0x99) || ((m_param[1] & 0x0f) > 0x09) || - (m_param[1] >= 0x60) || ((m_param[2] & 0x0f) > 0x09) || (m_param[2] >= 0x75)) { - CDROM_LOG("Invalid/out of range seek to %02x:%02x:%02x\n", m_param[0], m_param[1], m_param[2]); - } else { - set_loc.fromBCD(m_param); - - i = m_setSectorPlay.toLBA(); - i = abs(i - int(set_loc.toLBA())); - if (i > 16) m_seeked = SEEK_PENDING; - - m_setSector = set_loc; - m_setlocPending = 1; - } - break; - - case CdlReadN: - case CdlReadS: - case CdlPause: - StopCdda(); - StopReading(); - break; - - case CdlInit: - case CdlReset: - m_seeked = SEEK_DONE; - StopCdda(); - StopReading(); - break; - - case CdlSetmode: - CDROM_LOG("write1() Log: Setmode %x\n", m_param[0]); - if ((m_mode != MODE_STRSND) && (m_param[0] == MODE_STRSND)) { - xa_decode_reset(&m_xa); - } - m_mode = m_param[0]; - - // Squaresoft on PlayStation 1998 Collector's CD Vol. 1 - // - fixes choppy movie sound - if (m_play && (m_mode & MODE_CDDA) == 0) StopCdda(); - break; - } - } - - uint8_t read2(void) final { - unsigned char ret; - - if (m_read == 0) { - m_ctrl &= ~DRQSTS; // Data fifo empty - ret = 0; - } else { - ret = m_transfer[m_transferIndex]; - m_transferIndex++; - adjustTransferIndex(); - } - CDROM_IO_LOG("cdr r2: %02x\n", ret); - return ret; - } - - void write2(uint8_t rt) final { - CDROM_IO_LOG("cdr w2: %02x\n", rt); - switch (m_ctrl & 3) { - case 0: - if (m_paramC < 8) { // FIXME: size and wrapping - m_param[m_paramC++] = rt; - } - return; - case 1: - m_reg2 = rt; - setIrq(); - return; - case 2: - m_attenuatorLeftToLeftT = rt; - return; - case 3: - m_attenuatorRightToLeftT = rt; - return; - } - } - - uint8_t read3(void) final { - if (m_ctrl & 0x1) { - psxHu8(0x1803) = m_stat | 0xE0; - } else { - psxHu8(0x1803) = m_reg2 | 0xE0; - } - CDROM_IO_LOG("cdr r3: %02x\n", psxHu8(0x1803)); - return psxHu8(0x1803); - } - - void write3(uint8_t rt) final { - CDROM_IO_LOG("cdr w3: %02x\n", rt); - switch (m_ctrl & 3) { - case 0: - break; // transfer - case 1: - m_stat &= ~rt; - - if (rt & 0x40) m_paramC = 0; - return; - case 2: - m_attenuatorLeftToRightT = rt; - return; - case 3: - if (rt & 0x20) { - memcpy(&m_attenuatorLeftToLeft, &m_attenuatorLeftToLeftT, 4); - CDROM_IO_LOG("CD-XA Volume: %02x %02x | %02x %02x\n", m_attenuatorLeftToLeft, - m_attenuatorLeftToRight, m_attenuatorRightToLeft, m_attenuatorRightToRight); - } - return; - } - - if ((rt & 0x80) && m_read == 0) { - m_read = 1; - m_transferIndex = 0; - - switch (m_mode & (MODE_SIZE_2340 | MODE_SIZE_2328)) { - case MODE_SIZE_2328: - case MODE_SIZE_2048: - m_transferIndex += 12; - break; - - case MODE_SIZE_2340: - m_transferIndex += 0; - break; - - default: - break; - } - } - } - - void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) final { - uint32_t cdsize; - unsigned i; - uint8_t *ptr; - - CDROM_LOG("dma() Log: *** DMA 3 *** %x addr = %x size = %x\n", chcr, madr, bcr); - - switch (chcr) { - case 0x11000000: - case 0x11400100: - if (m_read == 0) { - CDROM_LOG("dma() Log: *** DMA 3 *** NOT READY\n"); - break; - } - - cdsize = (bcr & 0xffff) * 4; - - // Ape Escape: bcr = 0001 / 0000 - // - fix boot - if (cdsize == 0) { - switch (m_mode & (MODE_SIZE_2340 | MODE_SIZE_2328)) { - case MODE_SIZE_2340: - cdsize = 2340; - break; - case MODE_SIZE_2328: - cdsize = 2328; - break; - case MODE_SIZE_2048: - default: - cdsize = 2048; - break; - } - } - - ptr = (uint8_t *)PSXM(madr); - if (ptr == NULL) { - CDROM_LOG("dma() Log: *** DMA 3 *** NULL Pointer!\n"); - break; - } - - /* - GS CDX: Enhancement CD crash - - Setloc 0:0:0 - - CdlPlay - - Spams DMA3 and gets buffer overrun - */ - for (i = 0; i < cdsize; ++i) { - ptr[i] = m_transfer[m_transferIndex]; - m_transferIndex++; - adjustTransferIndex(); - } - if (PCSX::g_emulator->settings.get() - .get()) { - PCSX::g_emulator->m_debug->checkDMAwrite(3, madr, cdsize); - } - PCSX::g_emulator->m_cpu->Clear(madr, cdsize / 4); - // burst vs normal - if (chcr == 0x11400100) { - scheduleCDDMAIRQ((cdsize / 4) / 4); - } else if (chcr == 0x11000000) { - scheduleCDDMAIRQ((cdsize / 4) * 1); - } - return; - - default: - CDROM_LOG("dma() Log: Unknown cddma %x\n", chcr); - break; - } - - dmaInterrupt(); - } - - void dmaInterrupt() final { - if (HW_DMA3_CHCR & SWAP_LE32(0x01000000)) { - HW_DMA3_CHCR &= SWAP_LE32(~0x01000000); - DMA_INTERRUPT<3>(); - } - } - - void getCdInfo(void) { m_setSectorEnd = m_iso->getTD(0); } - - void reset() final { - m_reg1Mode = 0; - m_cmdProcess = 0; - m_ctrl = 0; - - memset(m_transfer, 0, sizeof(m_transfer)); - m_prev.reset(); - memset(m_param, 0, sizeof(m_param)); - memset(m_result, 0, sizeof(m_result)); - - m_paramC = 0; - m_resultC = 0; - m_resultP = 0; - m_resultReady = 0; - m_cmd = 0; - m_read = 0; - m_setlocPending = 0; - m_locationChanged = false; - m_reading = 0; - - m_setSectorPlay.reset(); - m_setSectorEnd.reset(); - m_setSector.reset(); - m_track = 0; - m_play = false; - m_muted = false; - m_mode = 0; - m_suceeded = true; - m_firstSector = 0; - - memset(&m_xa, 0, sizeof(m_xa)); - - m_irq = 0; - m_irqRepeated = 0; - m_eCycle = 0; - - m_seeked = 0; - m_readRescheduled = 0; - - m_fastForward = 0; - m_fastBackward = 0; - - m_attenuatorLeftToLeftT = 0; - m_attenuatorLeftToRightT = 0; - m_attenuatorRightToRightT = 0; - m_attenuatorRightToLeftT = 0; - - m_subq.index = 0; - m_subq.relative[0] = 0; - m_subq.relative[1] = 0; - m_subq.relative[2] = 0; - m_subq.absolute[0] = 0; - m_subq.absolute[1] = 0; - m_subq.absolute[2] = 0; - m_trackChanged = false; - - m_curTrack = 1; - m_file = 1; - m_channel = 1; - m_transferIndex = 0; - m_reg2 = 0x1f; - m_stat = NoIntr; - m_driveState = DRIVESTATE_STANDBY; - m_statP = STATUS_ROTATING; - - // BIOS player - default values - m_attenuatorLeftToLeft = 0x80; - m_attenuatorLeftToRight = 0x00; - m_attenuatorRightToLeft = 0x00; - m_attenuatorRightToRight = 0x80; - - getCdInfo(); - } - - void load() final { - getCdInfo(); - - // read right sub data - MSF tmp = m_prev; - readTrack(++tmp); - - if (m_play) { - Find_CurTrack(m_setSectorPlay); - } - } - - void lidInterrupt() final { - getCdInfo(); - StopCdda(); - lidSeekInterrupt(); - } + void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override {} void logCDROM(int command) { const auto delayedString = (command & 0x100) ? "[Delayed]" : ""; // log if this is a delayed CD-ROM IRQ @@ -1645,7 +144,7 @@ class CDRomImpl : public PCSX::CDRom { m_param[0], ret.m, ret.s, ret.f); } break; default: - if ((command & 0xff) > cdCmdEnumCount) { + if ((command & 0xff) > c_cdCmdEnumCount) { PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: CdlUnknown(0x%02X)\n", pc, delayedString, command & 0xff); } else { @@ -1660,7 +159,7 @@ class CDRomImpl : public PCSX::CDRom { } // namespace PCSX::CDRom *PCSX::CDRom::factory() { return new CDRomImpl; } -void PCSX::CDRom::check() { +void PCSX::CDRom::parseIso() { m_cdromId.clear(); m_cdromLabel.clear(); ISO9660Reader reader(m_iso); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 71caa1f46..774763759 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -50,9 +50,8 @@ class CDRom { CDRom() : m_iso(new CDRIso()) {} virtual ~CDRom() {} static CDRom* factory(); - bool isLidOpened() { return m_lidOpenTime < 0 || m_lidOpenTime > (int64_t)time(nullptr); } - void setLidOpenTime(int64_t time) { m_lidOpenTime = time; } - void check(); + bool isLidOpened() { return false; } + void parseIso(); std::shared_ptr getIso() { return m_iso; } void clearIso() { @@ -68,97 +67,26 @@ class CDRom { const std::string& getCDRomLabel() { return m_cdromLabel; } virtual void reset() = 0; - virtual void attenuate(int16_t* buf, int samples, int stereo) = 0; virtual void interrupt() = 0; - virtual void readInterrupt() = 0; - virtual void decodedBufferInterrupt() = 0; - virtual void lidSeekInterrupt() = 0; - virtual void playInterrupt() = 0; virtual void dmaInterrupt() = 0; - virtual void lidInterrupt() = 0; - virtual uint8_t read0(void) = 0; - virtual uint8_t read1(void) = 0; - virtual uint8_t read2(void) = 0; - virtual uint8_t read3(void) = 0; + virtual uint8_t read0() = 0; + virtual uint8_t read1() = 0; + virtual uint8_t read2() = 0; + virtual uint8_t read3() = 0; virtual void write0(uint8_t rt) = 0; virtual void write1(uint8_t rt) = 0; virtual void write2(uint8_t rt) = 0; virtual void write3(uint8_t rt) = 0; - virtual void load() = 0; virtual void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) = 0; protected: std::shared_ptr m_iso; - // savestate stuff starts here - uint8_t m_reg1Mode; - uint8_t m_reg2; - uint8_t m_cmdProcess; - uint8_t m_ctrl; - uint8_t m_stat; - - uint8_t m_statP; - - uint8_t m_transfer[PCSX::IEC60908b::FRAMESIZE_RAW]; - unsigned int m_transferIndex; - - MSF m_prev; - uint8_t m_param[8]; - uint8_t m_result[16]; - - uint8_t m_paramC; - uint8_t m_resultC; - uint8_t m_resultP; - uint8_t m_resultReady; - uint8_t m_cmd; - uint8_t m_read; - uint8_t m_setlocPending; - bool m_locationChanged; - uint32_t m_reading; - - MSF m_setSectorPlay; - MSF m_setSectorEnd; - MSF m_setSector; - uint8_t m_track; - bool m_play, m_muted; - int m_curTrack; - int m_mode, m_file, m_channel; - bool m_suceeded; - int m_firstSector; - - public: - // this belongs in the SPU, not here. - xa_decode_t m_xa; - - protected: - int64_t m_lidOpenTime = 0; - uint16_t m_irq; - uint8_t m_irqRepeated; - uint32_t m_eCycle; - - uint8_t m_seeked; - uint8_t m_readRescheduled; - - uint8_t m_driveState; - uint8_t m_fastForward; - uint8_t m_fastBackward; - - uint8_t m_attenuatorLeftToLeft, m_attenuatorLeftToRight; - uint8_t m_attenuatorRightToRight, m_attenuatorRightToLeft; - uint8_t m_attenuatorLeftToLeftT, m_attenuatorLeftToRightT; - uint8_t m_attenuatorRightToRightT, m_attenuatorRightToLeftT; - - struct { - uint8_t track; - uint8_t index; - uint8_t relative[3]; - uint8_t absolute[3]; - } m_subq; - bool m_trackChanged; - // end savestate friend SaveStates::SaveState SaveStates::constructSaveState(); + uint8_t m_param[32] = {0}; + private: friend class Widgets::IsoBrowser; std::string m_cdromId; diff --git a/src/core/r3000a.cc b/src/core/r3000a.cc index 519398989..90c8e4077 100644 --- a/src/core/r3000a.cc +++ b/src/core/r3000a.cc @@ -278,29 +278,6 @@ void PCSX::R3000Acpu::restorePCdrvFile(const std::filesystem::path& filename, ui } void PCSX::R3000Acpu::branchTest() { -#if 0 - if( SPU_async ) - { - static int init; - int elapsed; - - if( init == 0 ) { - // 10 apu cycles - // - Final Fantasy Tactics (distorted - dropped sound effects) - m_regs.intCycle[PSXINT_SPUASYNC].cycle = g_emulator->m_psxClockSpeed / 44100 * 10; - - init = 1; - } - - elapsed = m_regs.cycle - m_regs.intCycle[PSXINT_SPUASYNC].sCycle; - if (elapsed >= m_regs.intCycle[PSXINT_SPUASYNC].cycle) { - SPU_async( elapsed ); - - m_regs.intCycle[PSXINT_SPUASYNC].sCycle = m_regs.cycle; - } - } -#endif - const uint32_t cycle = m_regs.cycle; if (cycle >= PCSX::g_emulator->m_counters->m_psxNextCounter) PCSX::g_emulator->m_counters->update(); @@ -335,16 +312,12 @@ void PCSX::R3000Acpu::branchTest() { checkAndUpdate(PSXINT_SIO, g_emulator->m_sio->interrupt); checkAndUpdate(PSXINT_SIO1, g_emulator->m_sio1->interrupt); checkAndUpdate(PSXINT_CDR, g_emulator->m_cdrom->interrupt); - checkAndUpdate(PSXINT_CDREAD, g_emulator->m_cdrom->readInterrupt); checkAndUpdate(PSXINT_GPUDMA, GPU::gpuInterrupt); checkAndUpdate(PSXINT_MDECOUTDMA, g_emulator->m_mdec->mdec1Interrupt); checkAndUpdate(PSXINT_SPUDMA, spuInterrupt); checkAndUpdate(PSXINT_MDECINDMA, g_emulator->m_mdec->mdec0Interrupt); checkAndUpdate(PSXINT_GPUOTCDMA, gpuotcInterrupt); checkAndUpdate(PSXINT_CDRDMA, g_emulator->m_cdrom->dmaInterrupt); - checkAndUpdate(PSXINT_CDRPLAY, g_emulator->m_cdrom->playInterrupt); - checkAndUpdate(PSXINT_CDRDBUF, g_emulator->m_cdrom->decodedBufferInterrupt); - checkAndUpdate(PSXINT_CDRLID, g_emulator->m_cdrom->lidSeekInterrupt); m_regs.lowestTarget = lowestTarget; } if ((psxHu32(0x1070) & psxHu32(0x1074)) && ((m_regs.CP0.n.Status & 0x401) == 0x401)) { diff --git a/src/core/r3000a.h b/src/core/r3000a.h index b369b3a8b..2f696fc79 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -177,18 +177,12 @@ enum { PSXINT_SIO = 0, PSXINT_SIO1, PSXINT_CDR, - PSXINT_CDREAD, PSXINT_GPUDMA, PSXINT_MDECOUTDMA, PSXINT_SPUDMA, - PSXINT_GPUBUSY, PSXINT_MDECINDMA, PSXINT_GPUOTCDMA, PSXINT_CDRDMA, - PSXINT_SPUASYNC, - PSXINT_CDRDBUF, - PSXINT_CDRLID, - PSXINT_CDRPLAY }; struct psxRegisters { diff --git a/src/core/sstate.cc b/src/core/sstate.cc index 3d7c92fa2..72e5e65c0 100644 --- a/src/core/sstate.cc +++ b/src/core/sstate.cc @@ -107,66 +107,14 @@ PCSX::SaveStates::SaveState PCSX::SaveStates::constructSaveState() { SIOMCD2Sector{g_emulator->m_sio->m_memoryCard[1].m_sector}, SIOMCD2DataOffset{g_emulator->m_sio->m_memoryCard[1].m_dataOffset}, }, - CDRom { - CDReg1Mode { g_emulator->m_cdrom->m_reg1Mode }, - CDReg2 { g_emulator->m_cdrom->m_reg2 }, - CDCmdProcess { g_emulator->m_cdrom->m_cmdProcess }, - CDCtrl { g_emulator->m_cdrom->m_ctrl }, - CDStat { g_emulator->m_cdrom->m_stat }, - CDStatP { g_emulator->m_cdrom->m_statP }, - CDTransfer { reinterpret_cast(g_emulator->m_cdrom->m_transfer) }, - CDTransferIndex { g_emulator->m_cdrom->m_transferIndex }, - CDPrev { g_emulator->m_cdrom->m_prev.data }, - CDParam { g_emulator->m_cdrom->m_param }, - CDResult { g_emulator->m_cdrom->m_result }, - CDParamC { g_emulator->m_cdrom->m_paramC }, - CDResultC { g_emulator->m_cdrom->m_resultC }, - CDResultP { g_emulator->m_cdrom->m_resultP }, - CDResultReady { g_emulator->m_cdrom->m_resultReady }, - CDCmd { g_emulator->m_cdrom->m_cmd }, - CDRead { g_emulator->m_cdrom->m_read }, - CDSetLocPending { g_emulator->m_cdrom->m_setlocPending }, - CDReading { g_emulator->m_cdrom->m_reading }, - CDSetSectorPlay { g_emulator->m_cdrom->m_setSectorPlay.data }, - CDSetSectorEnd { g_emulator->m_cdrom->m_setSectorEnd.data }, - CDSetSector { g_emulator->m_cdrom->m_setSector.data }, - CDTrack { g_emulator->m_cdrom->m_track }, - CDPlay { g_emulator->m_cdrom->m_play }, - CDMuted { g_emulator->m_cdrom->m_muted }, - CDCurTrack { g_emulator->m_cdrom->m_curTrack }, - CDMode { g_emulator->m_cdrom->m_mode }, - CDFile { g_emulator->m_cdrom->m_file }, - CDChannel { g_emulator->m_cdrom->m_channel }, - CDSuceeded { g_emulator->m_cdrom->m_suceeded }, - CDFirstSector { g_emulator->m_cdrom->m_firstSector }, - CDIRQ { g_emulator->m_cdrom->m_irq }, - CDIrqRepeated { g_emulator->m_cdrom->m_irqRepeated }, - CDECycle { g_emulator->m_cdrom->m_eCycle }, - CDSeeked { g_emulator->m_cdrom->m_seeked }, - CDReadRescheduled { g_emulator->m_cdrom->m_readRescheduled }, - CDDriveState { g_emulator->m_cdrom->m_driveState }, - CDFastForward { g_emulator->m_cdrom->m_fastForward }, - CDFastBackward { g_emulator->m_cdrom->m_fastBackward }, - CDAttenuatorLeftToLeft { g_emulator->m_cdrom->m_attenuatorLeftToLeft }, - CDAttenuatorLeftToRight { g_emulator->m_cdrom->m_attenuatorLeftToRight }, - CDAttenuatorRightToRight { g_emulator->m_cdrom->m_attenuatorRightToRight }, - CDAttenuatorRightToLeft { g_emulator->m_cdrom->m_attenuatorRightToLeft }, - CDAttenuatorLeftToLeftT { g_emulator->m_cdrom->m_attenuatorLeftToLeftT }, - CDAttenuatorLeftToRightT { g_emulator->m_cdrom->m_attenuatorLeftToRightT }, - CDAttenuatorRightToRightT { g_emulator->m_cdrom->m_attenuatorRightToRightT }, - CDAttenuatorRightToLeftT { g_emulator->m_cdrom->m_attenuatorRightToLeftT }, - CDSubQTrack { g_emulator->m_cdrom->m_subq.track }, - CDSubQIndex { g_emulator->m_cdrom->m_subq.index }, - CDSubQRelative { g_emulator->m_cdrom->m_subq.relative }, - CDSubQAbsolute { g_emulator->m_cdrom->m_subq.absolute }, - CDTrackChanged { g_emulator->m_cdrom->m_trackChanged }, - CDLocationChanged { g_emulator->m_cdrom->m_locationChanged }, - }, Hardware {}, Counters {}, MDEC {}, PCdrvFilesField {}, CallStacks {}, + CDRom { + CDParam { g_emulator->m_cdrom->m_param }, + }, }; // clang-format on } @@ -182,8 +130,8 @@ std::string PCSX::SaveStates::save() { SaveState state = constructSaveState(); SaveStateWrapper wrapper(state); - state.get().get().value = "PCSX-Redux SaveState v3"; - state.get().get().value = 3; + state.get().get().value = "PCSX-Redux SaveState v4"; + state.get().get().value = 4; g_emulator->m_gpu->serialize(&wrapper); g_emulator->m_spu->save(state.get()); @@ -288,7 +236,7 @@ bool PCSX::SaveStates::load(std::string_view data) { return false; } - if (state.get().get().value != 3) { + if (state.get().get().value != 4) { return false; } @@ -302,13 +250,16 @@ bool PCSX::SaveStates::load(std::string_view data) { g_emulator->m_cpu->m_regs.pc &= ~3; g_emulator->m_gpu->deserialize(&wrapper); g_emulator->m_spu->load(state.get()); +#if 0 g_emulator->m_cdrom->load(); +#endif g_emulator->m_counters->deserialize(&wrapper); g_emulator->m_mdec->deserialize(&wrapper); auto& xa = state.get().get(); +#if 0 g_emulator->m_cdrom->m_xa.freq = xa.get().value; g_emulator->m_cdrom->m_xa.nbits = xa.get().value; g_emulator->m_cdrom->m_xa.nsamples = xa.get().value; @@ -321,6 +272,7 @@ bool PCSX::SaveStates::load(std::string_view data) { g_emulator->m_cdrom->m_xa.right.y1 = right.get().value; xa.get().copyTo(reinterpret_cast(g_emulator->m_cdrom->m_xa.pcm)); g_emulator->m_spu->playADPCMchannel(&g_emulator->m_cdrom->m_xa); +#endif g_emulator->m_cpu->closeAllPCdevFiles(); for (auto& file : state.get().value) { diff --git a/src/core/sstate.h b/src/core/sstate.h index 3745e8f2d..22802a3ea 100644 --- a/src/core/sstate.h +++ b/src/core/sstate.h @@ -170,76 +170,7 @@ typedef Protobuf::Message SIO; typedef Protobuf::MessageField SIOField; - -// skip id 1 -typedef Protobuf::FieldRef CDReg1Mode; -typedef Protobuf::FieldRef CDReg2; -typedef Protobuf::FieldRef CDCmdProcess; -typedef Protobuf::FieldRef CDCtrl; -typedef Protobuf::FieldRef CDStat; -typedef Protobuf::FieldRef CDStatP; -typedef Protobuf::FieldPtr, TYPESTRING("transfer"), 8> CDTransfer; -typedef Protobuf::FieldRef CDTransferIndex; -typedef Protobuf::FieldPtr, TYPESTRING("prev"), 10> CDPrev; -typedef Protobuf::FieldPtr, TYPESTRING("param"), 11> CDParam; -typedef Protobuf::FieldPtr, TYPESTRING("result"), 12> CDResult; -typedef Protobuf::FieldRef CDParamC; -// skip id 14 -typedef Protobuf::FieldRef CDResultC; -typedef Protobuf::FieldRef CDResultP; -typedef Protobuf::FieldRef CDResultReady; -typedef Protobuf::FieldRef CDCmd; -typedef Protobuf::FieldRef CDRead; -typedef Protobuf::FieldRef CDSetLocPending; -typedef Protobuf::FieldRef CDReading; -// skip id 22 -// skip id 23 -typedef Protobuf::FieldPtr, TYPESTRING("set_sector_play"), 24> CDSetSectorPlay; -typedef Protobuf::FieldPtr, TYPESTRING("set_sector_end"), 25> CDSetSectorEnd; -typedef Protobuf::FieldPtr, TYPESTRING("set_sector"), 26> CDSetSector; -typedef Protobuf::FieldRef CDTrack; -typedef Protobuf::FieldRef CDPlay; -typedef Protobuf::FieldRef CDMuted; -typedef Protobuf::FieldRef CDCurTrack; -typedef Protobuf::FieldRef CDMode; -typedef Protobuf::FieldRef CDFile; -typedef Protobuf::FieldRef CDChannel; -typedef Protobuf::FieldRef CDSuceeded; -typedef Protobuf::FieldRef CDFirstSector; -typedef Protobuf::FieldRef CDIRQ; -typedef Protobuf::FieldRef CDIrqRepeated; -typedef Protobuf::FieldRef CDECycle; -typedef Protobuf::FieldRef CDSeeked; -typedef Protobuf::FieldRef CDReadRescheduled; -typedef Protobuf::FieldRef CDDriveState; -typedef Protobuf::FieldRef CDFastForward; -typedef Protobuf::FieldRef CDFastBackward; -typedef Protobuf::FieldRef CDAttenuatorLeftToLeft; -typedef Protobuf::FieldRef CDAttenuatorLeftToRight; -typedef Protobuf::FieldRef CDAttenuatorRightToRight; -typedef Protobuf::FieldRef CDAttenuatorRightToLeft; -typedef Protobuf::FieldRef CDAttenuatorLeftToLeftT; -typedef Protobuf::FieldRef CDAttenuatorLeftToRightT; -typedef Protobuf::FieldRef CDAttenuatorRightToRightT; -typedef Protobuf::FieldRef CDAttenuatorRightToLeftT; -typedef Protobuf::FieldRef CDSubQTrack; -typedef Protobuf::FieldRef CDSubQIndex; -typedef Protobuf::FieldPtr, TYPESTRING("subq_relative"), 54> CDSubQRelative; -typedef Protobuf::FieldPtr, TYPESTRING("subq_absolute"), 55> CDSubQAbsolute; -typedef Protobuf::FieldRef CDTrackChanged; -typedef Protobuf::FieldRef CDLocationChanged; - -typedef Protobuf::Message< - TYPESTRING("CDRom"), CDReg1Mode, CDReg2, CDCmdProcess, CDCtrl, CDStat, CDStatP, CDTransfer, CDTransferIndex, CDPrev, - CDParam, CDResult, CDParamC, CDResultC, CDResultP, CDResultReady, CDCmd, CDRead, CDSetLocPending, CDReading, - CDSetSectorPlay, CDSetSectorEnd, CDSetSector, CDTrack, CDPlay, CDMuted, CDCurTrack, CDMode, CDFile, CDChannel, - CDSuceeded, CDFirstSector, CDIRQ, CDIrqRepeated, CDECycle, CDSeeked, CDReadRescheduled, CDDriveState, CDFastForward, - CDFastBackward, CDAttenuatorLeftToLeft, CDAttenuatorLeftToRight, CDAttenuatorRightToRight, CDAttenuatorRightToLeft, - CDAttenuatorLeftToLeftT, CDAttenuatorLeftToRightT, CDAttenuatorRightToRightT, CDAttenuatorRightToLeftT, CDSubQTrack, - CDSubQIndex, CDSubQRelative, CDSubQAbsolute, CDTrackChanged, CDLocationChanged> - CDRom; -typedef Protobuf::MessageField CDRomField; - +// skip id 8 typedef Protobuf::EmptyMessage Hardware; typedef Protobuf::MessageField HardwareField; @@ -302,10 +233,13 @@ typedef Protobuf::RepeatedVariableField typedef Protobuf::Field CallStacksCurrentSP; typedef Protobuf::Message CallStacks; typedef Protobuf::MessageField CallStacksField; +typedef Protobuf::FieldPtr, TYPESTRING("param"), 1> CDParam; +typedef Protobuf::Message CDRom; +typedef Protobuf::MessageField CDRomField; typedef Protobuf::Message + GPUField, SPUField, SIOField, HardwareField, CountersField, MDECField, PCdrvFilesField, + CallStacksField, CDRomField> SaveState; typedef Protobuf::ProtoFilem_cdrom->setIso(new CDRIso()); - PCSX::g_emulator->m_cdrom->check(); + PCSX::g_emulator->m_cdrom->parseIso(); } if (ImGui::MenuItem(_("Load binary"))) { showOpenBinaryDialog = true; @@ -957,16 +957,13 @@ void PCSX::GUI::endFrame() { ImGui::Separator(); if (ImGui::MenuItem(_("Open LID"))) { - PCSX::g_emulator->m_cdrom->setLidOpenTime(-1); - PCSX::g_emulator->m_cdrom->lidInterrupt(); + // Open lid forever } if (ImGui::MenuItem(_("Close LID"))) { - PCSX::g_emulator->m_cdrom->setLidOpenTime(0); - PCSX::g_emulator->m_cdrom->lidInterrupt(); + // Close lid forever } if (ImGui::MenuItem(_("Open and close LID"))) { - PCSX::g_emulator->m_cdrom->setLidOpenTime((int64_t)time(nullptr) + 2); - PCSX::g_emulator->m_cdrom->lidInterrupt(); + // Open lid, and schedule a close lid } ImGui::Separator(); if (ImGui::MenuItem(_("Reboot"))) { @@ -1193,7 +1190,7 @@ in Configuration->Emulation, restart PCSX-Redux, then try again.)")); std::vector fileToOpen = m_openIsoFileDialog.selected(); if (!fileToOpen.empty()) { PCSX::g_emulator->m_cdrom->setIso(new CDRIso(reinterpret_cast(fileToOpen[0].c_str()))); - PCSX::g_emulator->m_cdrom->check(); + PCSX::g_emulator->m_cdrom->parseIso(); } } @@ -2108,7 +2105,7 @@ void PCSX::GUI::magicOpen(const char* pathStr) { g_system->softReset(); } else { PCSX::g_emulator->m_cdrom->setIso(new CDRIso(pathStr)); - PCSX::g_emulator->m_cdrom->check(); + PCSX::g_emulator->m_cdrom->parseIso(); } free(extension); diff --git a/src/gui/widgets/isobrowser.cc b/src/gui/widgets/isobrowser.cc index 9eed668ed..bf139d389 100644 --- a/src/gui/widgets/isobrowser.cc +++ b/src/gui/widgets/isobrowser.cc @@ -78,7 +78,7 @@ void PCSX::Widgets::IsoBrowser::draw(CDRom* cdrom, const char* title) { showOpenIsoFileDialog = ImGui::MenuItem(_("Open Disk Image")); if (ImGui::MenuItem(_("Close Disk Image"))) { g_emulator->m_cdrom->setIso(new CDRIso()); - g_emulator->m_cdrom->check(); + g_emulator->m_cdrom->parseIso(); } ImGui::EndMenu(); } @@ -98,7 +98,7 @@ void PCSX::Widgets::IsoBrowser::draw(CDRom* cdrom, const char* title) { std::vector fileToOpen = m_openIsoFileDialog.selected(); if (!fileToOpen.empty()) { g_emulator->m_cdrom->setIso(new CDRIso(reinterpret_cast(fileToOpen[0].c_str()))); - g_emulator->m_cdrom->check(); + g_emulator->m_cdrom->parseIso(); } } auto iso = cdrom->m_iso.get(); diff --git a/src/main/main.cc b/src/main/main.cc index 59f7284c8..68269c959 100644 --- a/src/main/main.cc +++ b/src/main/main.cc @@ -252,7 +252,7 @@ int pcsxMain(int argc, char **argv) { if (isoToOpen.empty()) isoToOpen = args.get("loadiso", ""); if (isoToOpen.empty()) isoToOpen = args.get("disk", ""); if (!isoToOpen.empty()) PCSX::g_emulator->m_cdrom->setIso(new PCSX::CDRIso(isoToOpen)); - PCSX::g_emulator->m_cdrom->check(); + PCSX::g_emulator->m_cdrom->parseIso(); auto argPCdrvBase = args.get("pcdrvbase"); if (args.get("pcdrv", false)) { debugSettings.get().value = true; From aa236f7c08f9dffe6140cf2ceb76442e5cd1e9b6 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 5 Dec 2022 22:22:32 -0800 Subject: [PATCH 002/185] We... shouldn't have this delayed nonsense. --- src/core/cdrom.cc | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 02cb26d8a..cc98e5a4b 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -86,27 +86,23 @@ class CDRomImpl final : public PCSX::CDRom { void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override {} void logCDROM(int command) { - const auto delayedString = (command & 0x100) ? "[Delayed]" : ""; // log if this is a delayed CD-ROM IRQ uint32_t pc = PCSX::g_emulator->m_cpu->m_regs.pc; switch (command & 0xff) { // TODO: decode more commands case CdlTest: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: CdlTest %02x\n", pc, delayedString, - m_param[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlTest %02x\n", pc, m_param[0]); break; case CdlSetloc: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: CdlSetloc %02x:%02x:%02x\n", pc, - delayedString, m_param[0], m_param[1], m_param[2]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetloc %02x:%02x:%02x\n", pc, + m_param[0], m_param[1], m_param[2]); break; case CdlPlay: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: CdlPlay %i\n", pc, delayedString, - m_param[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlPlay %i\n", pc, m_param[0]); break; case CdlSetfilter: - PCSX::g_system->log(PCSX::LogClass::CDROM, - "%08x [CDROM]%s Command: CdlSetfilter file: %i, channel: %i\n", pc, delayedString, - m_param[0], m_param[1]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetfilter file: %i, channel: %i\n", + pc, m_param[0], m_param[1]); break; case CdlSetmode: { auto mode = m_param[0]; @@ -130,25 +126,25 @@ class CDRomImpl final : public PCSX::CDRom { } if (mode & 0x40) modeDecode += " RealTimePlay"; modeDecode += mode & 0x80 ? " @2x" : " @1x"; - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: CdlSetmode %02x (%s)\n", pc, - delayedString, m_param[0], modeDecode); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetmode %02x (%s)\n", pc, + m_param[0], modeDecode); } break; case CdlGetTN: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: CdlGetTN (returns %i)\n", pc, - delayedString, m_iso->getTN()); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlGetTN (returns %i)\n", pc, + m_iso->getTN()); break; case CdlGetTD: { auto ret = m_iso->getTD(m_param[0]); PCSX::g_system->log(PCSX::LogClass::CDROM, - "%08x [CDROM]%s Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", pc, delayedString, - m_param[0], ret.m, ret.s, ret.f); + "%08x [CDROM] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", pc, m_param[0], + ret.m, ret.s, ret.f); } break; default: if ((command & 0xff) > c_cdCmdEnumCount) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: CdlUnknown(0x%02X)\n", pc, - delayedString, command & 0xff); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlUnknown(0x%02X)\n", pc, + command & 0xff); } else { - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM]%s Command: %s\n", pc, delayedString, + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: %s\n", pc, magic_enum::enum_names()[command & 0xff]); } break; From ff0c7f8333463e1af28f09f8efa0159cb5b33f71 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 6 Dec 2022 21:38:51 -0800 Subject: [PATCH 003/185] First pieces of the state machine in place. --- src/core/cdrom.cc | 85 +++++++++++++++++++++------ src/core/cdrom.h | 16 +++++- src/core/sstate.cc | 139 ++++++++++++++++++++++++--------------------- src/core/sstate.h | 21 ++++++- 4 files changed, 177 insertions(+), 84 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index cc98e5a4b..c15f9a943 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -70,42 +70,95 @@ class CDRomImpl final : public PCSX::CDRom { static constexpr size_t c_cdCmdEnumCount = magic_enum::enum_count(); - void reset() override {} + void reset() override { + m_dataFIFOIndex = 0; + m_dataFIFOSize = 0; + m_paramFIFOSize = 0; + m_responseFIFOIndex = 0; + m_responseFIFOSize = 0; + m_registerIndex = 0; + m_busy = false; + m_state = 0; + m_command = 0; + } void interrupt() override {} void dmaInterrupt() override {} - uint8_t read0() override { return 0; } - uint8_t read1() override { return 0; } - uint8_t read2() override { return 0; } + + uint8_t read0() override { + uint8_t v01 = m_registerIndex & 3; + uint8_t adpcmPlaying = 0; + uint8_t v3 = m_paramFIFOSize == 0 ? 0x08 : 0; + uint8_t v4 = m_paramFIFOSize == 16 ? 0x10 : 0; + uint8_t v5 = responseFIFOEmpty() ? 0x20 : 0; + uint8_t v6 = m_dataFIFOSize == m_dataFIFOIndex ? 0x40 : 0; + uint8_t v7 = m_busy ? 0x80 : 0; + + return v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7; + } + + uint8_t read1() override { + if (responseFIFOEmpty()) return 0; + return m_responseFIFO[m_responseFIFOIndex++]; + } + + uint8_t read2() override { + if (dataFIFOEmpty()) return 0; + return m_dataFIFO[m_dataFIFOIndex++]; + } + uint8_t read3() override { return 0; } - void write0(uint8_t rt) override {} - void write1(uint8_t rt) override {} + + void write0(uint8_t rt) override { m_registerIndex = rt & 3; } + + void write1(uint8_t rt) override { + switch (m_registerIndex) { + case 0: { + if (m_busy) { + // The CD-Rom controller is already executing a command. + // This basically results in undefined behavior. + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom command while controller is busy"); + PCSX::g_system->pause(); + } + m_busy = true; + m_command = rt; + if (PCSX::g_emulator->settings.get() + .get()) { + logCDROM(rt); + } + startCommand(rt); + } break; + } + } + void write2(uint8_t rt) override {} + void write3(uint8_t rt) override {} void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override {} - void logCDROM(int command) { + void startCommand(uint8_t command) {} + + void logCDROM(uint8_t command) { uint32_t pc = PCSX::g_emulator->m_cpu->m_regs.pc; switch (command & 0xff) { - // TODO: decode more commands case CdlTest: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlTest %02x\n", pc, m_param[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlTest %02x\n", pc, m_paramFIFO[0]); break; case CdlSetloc: PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetloc %02x:%02x:%02x\n", pc, - m_param[0], m_param[1], m_param[2]); + m_paramFIFO[0], m_paramFIFO[1], m_paramFIFO[2]); break; case CdlPlay: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlPlay %i\n", pc, m_param[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlPlay %i\n", pc, m_paramFIFO[0]); break; case CdlSetfilter: PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetfilter file: %i, channel: %i\n", - pc, m_param[0], m_param[1]); + pc, m_paramFIFO[0], m_paramFIFO[1]); break; case CdlSetmode: { - auto mode = m_param[0]; + auto mode = m_paramFIFO[0]; std::string modeDecode = mode & 1 ? "CDDA" : "DATA"; if (mode & 2) modeDecode += " Autopause"; if (mode & 4) modeDecode += " Report"; @@ -127,16 +180,16 @@ class CDRomImpl final : public PCSX::CDRom { if (mode & 0x40) modeDecode += " RealTimePlay"; modeDecode += mode & 0x80 ? " @2x" : " @1x"; PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetmode %02x (%s)\n", pc, - m_param[0], modeDecode); + m_paramFIFO[0], modeDecode); } break; case CdlGetTN: PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlGetTN (returns %i)\n", pc, m_iso->getTN()); break; case CdlGetTD: { - auto ret = m_iso->getTD(m_param[0]); + auto ret = m_iso->getTD(m_paramFIFO[0]); PCSX::g_system->log(PCSX::LogClass::CDROM, - "%08x [CDROM] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", pc, m_param[0], + "%08x [CDROM] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", pc, m_paramFIFO[0], ret.m, ret.s, ret.f); } break; default: diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 774763759..c32d446bd 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -85,7 +85,21 @@ class CDRom { std::shared_ptr m_iso; friend SaveStates::SaveState SaveStates::constructSaveState(); - uint8_t m_param[32] = {0}; + bool dataFIFOEmpty() { return m_dataFIFOIndex == m_dataFIFOSize; } + bool responseFIFOEmpty() { return m_responseFIFOIndex == m_responseFIFOSize; } + + uint8_t m_dataFIFO[2352] = {0}; + uint8_t m_paramFIFO[16] = {0}; + uint8_t m_responseFIFO[16] = {0}; + uint32_t m_dataFIFOIndex = 0; + uint32_t m_dataFIFOSize = 0; + uint8_t m_paramFIFOSize = 0; + uint8_t m_responseFIFOIndex = 0; + uint8_t m_responseFIFOSize = 0; + uint8_t m_registerIndex = 0; + bool m_busy = false; + uint8_t m_state = 0; + uint8_t m_command = 0; private: friend class Widgets::IsoBrowser; diff --git a/src/core/sstate.cc b/src/core/sstate.cc index 72e5e65c0..b6b794079 100644 --- a/src/core/sstate.cc +++ b/src/core/sstate.cc @@ -31,68 +31,67 @@ #include "spu/interface.h" PCSX::SaveStates::SaveState PCSX::SaveStates::constructSaveState() { - // clang-format off - return SaveState { - SaveStateInfo { - VersionString {}, - Version {}, + return SaveState{ + SaveStateInfo{ + VersionString{}, + Version{}, }, - Thumbnail {}, - Memory { - RAM { g_emulator->m_mem->m_psxM }, - ROM { g_emulator->m_mem->m_psxR }, - Parallel { g_emulator->m_mem->m_psxP }, - HardwareMemory { g_emulator->m_mem->m_psxH }, + Thumbnail{}, + Memory{ + RAM{g_emulator->m_mem->m_psxM}, + ROM{g_emulator->m_mem->m_psxR}, + Parallel{g_emulator->m_mem->m_psxP}, + HardwareMemory{g_emulator->m_mem->m_psxH}, }, - Registers { - GPR { g_emulator->m_cpu->m_regs.GPR.r }, - CP0 { g_emulator->m_cpu->m_regs.CP0.r }, - CP2D { g_emulator->m_cpu->m_regs.CP2D.r }, - CP2C { g_emulator->m_cpu->m_regs.CP2C.r }, - PC { g_emulator->m_cpu->m_regs.pc }, - Code { g_emulator->m_cpu->m_regs.code }, - Cycle { g_emulator->m_cpu->m_regs.cycle }, - Interrupt { g_emulator->m_cpu->m_regs.interrupt }, - ICacheAddr { g_emulator->m_cpu->m_regs.ICache_Addr }, - ICacheCode { g_emulator->m_cpu->m_regs.ICache_Code }, - NextIsDelaySlot { g_emulator->m_cpu->m_nextIsDelaySlot }, - DelaySlotInfo1 { - DelaySlotIndex { g_emulator->m_cpu->m_delayedLoadInfo[0].index }, - DelaySlotValue { g_emulator->m_cpu->m_delayedLoadInfo[0].value }, - DelaySlotMask { g_emulator->m_cpu->m_delayedLoadInfo[0].mask }, - DelaySlotPcValue { g_emulator->m_cpu->m_delayedLoadInfo[0].pcValue }, - DelaySlotActive { g_emulator->m_cpu->m_delayedLoadInfo[0].active }, - DelaySlotPcActive { g_emulator->m_cpu->m_delayedLoadInfo[0].pcActive }, - DelaySlotFromLink { g_emulator->m_cpu->m_delayedLoadInfo[0].fromLink } + Registers{ + GPR{g_emulator->m_cpu->m_regs.GPR.r}, + CP0{g_emulator->m_cpu->m_regs.CP0.r}, + CP2D{g_emulator->m_cpu->m_regs.CP2D.r}, + CP2C{g_emulator->m_cpu->m_regs.CP2C.r}, + PC{g_emulator->m_cpu->m_regs.pc}, + Code{g_emulator->m_cpu->m_regs.code}, + Cycle{g_emulator->m_cpu->m_regs.cycle}, + Interrupt{g_emulator->m_cpu->m_regs.interrupt}, + ICacheAddr{g_emulator->m_cpu->m_regs.ICache_Addr}, + ICacheCode{g_emulator->m_cpu->m_regs.ICache_Code}, + NextIsDelaySlot{g_emulator->m_cpu->m_nextIsDelaySlot}, + DelaySlotInfo1{ + DelaySlotIndex{g_emulator->m_cpu->m_delayedLoadInfo[0].index}, + DelaySlotValue{g_emulator->m_cpu->m_delayedLoadInfo[0].value}, + DelaySlotMask{g_emulator->m_cpu->m_delayedLoadInfo[0].mask}, + DelaySlotPcValue{g_emulator->m_cpu->m_delayedLoadInfo[0].pcValue}, + DelaySlotActive{g_emulator->m_cpu->m_delayedLoadInfo[0].active}, + DelaySlotPcActive{g_emulator->m_cpu->m_delayedLoadInfo[0].pcActive}, + DelaySlotFromLink{g_emulator->m_cpu->m_delayedLoadInfo[0].fromLink}, }, - DelaySlotInfo2 { - DelaySlotIndex { g_emulator->m_cpu->m_delayedLoadInfo[1].index }, - DelaySlotValue { g_emulator->m_cpu->m_delayedLoadInfo[1].value }, - DelaySlotMask { g_emulator->m_cpu->m_delayedLoadInfo[1].mask }, - DelaySlotPcValue { g_emulator->m_cpu->m_delayedLoadInfo[1].pcValue }, - DelaySlotActive { g_emulator->m_cpu->m_delayedLoadInfo[1].active }, - DelaySlotPcActive { g_emulator->m_cpu->m_delayedLoadInfo[1].pcActive }, - DelaySlotFromLink { g_emulator->m_cpu->m_delayedLoadInfo[1].fromLink } + DelaySlotInfo2{ + DelaySlotIndex{g_emulator->m_cpu->m_delayedLoadInfo[1].index}, + DelaySlotValue{g_emulator->m_cpu->m_delayedLoadInfo[1].value}, + DelaySlotMask{g_emulator->m_cpu->m_delayedLoadInfo[1].mask}, + DelaySlotPcValue{g_emulator->m_cpu->m_delayedLoadInfo[1].pcValue}, + DelaySlotActive{g_emulator->m_cpu->m_delayedLoadInfo[1].active}, + DelaySlotPcActive{g_emulator->m_cpu->m_delayedLoadInfo[1].pcActive}, + DelaySlotFromLink{g_emulator->m_cpu->m_delayedLoadInfo[1].fromLink}, }, - CurrentDelayedLoad { g_emulator->m_cpu->m_currentDelayedLoad }, - IntTargetsField { g_emulator->m_cpu->m_regs.intTargets }, - InISR { g_emulator->m_cpu->m_inISR }, + CurrentDelayedLoad{g_emulator->m_cpu->m_currentDelayedLoad}, + IntTargetsField{g_emulator->m_cpu->m_regs.intTargets}, + InISR{g_emulator->m_cpu->m_inISR}, }, - GPU {}, - SPU {}, - SIO { - SIOBuffer { g_emulator->m_sio->m_buffer }, - SIOStatusReg { g_emulator->m_sio->m_regs.status }, - SIOModeReg { g_emulator->m_sio->m_regs.mode }, - SIOCtrlReg { g_emulator->m_sio->m_regs.control }, - SIOBaudReg { g_emulator->m_sio->m_regs.baud }, - SIOBufferMaxIndex { g_emulator->m_sio->m_maxBufferIndex }, - SIOBufferIndex { g_emulator->m_sio->m_bufferIndex }, - SIOPadState { g_emulator->m_sio->m_padState }, - SIOCurrentDevice { g_emulator->m_sio->m_currentDevice }, - SIOMCD1TempBuffer { g_emulator->m_sio->m_memoryCard[0].m_tempBuffer }, - SIOMCD1DirectoryFlag { g_emulator->m_sio->m_memoryCard[0].m_directoryFlag }, - SIOMCD1ChecksumIn{ g_emulator->m_sio->m_memoryCard[0].m_checksumIn}, + GPU{}, + SPU{}, + SIO{ + SIOBuffer{g_emulator->m_sio->m_buffer}, + SIOStatusReg{g_emulator->m_sio->m_regs.status}, + SIOModeReg{g_emulator->m_sio->m_regs.mode}, + SIOCtrlReg{g_emulator->m_sio->m_regs.control}, + SIOBaudReg{g_emulator->m_sio->m_regs.baud}, + SIOBufferMaxIndex{g_emulator->m_sio->m_maxBufferIndex}, + SIOBufferIndex{g_emulator->m_sio->m_bufferIndex}, + SIOPadState{g_emulator->m_sio->m_padState}, + SIOCurrentDevice{g_emulator->m_sio->m_currentDevice}, + SIOMCD1TempBuffer{g_emulator->m_sio->m_memoryCard[0].m_tempBuffer}, + SIOMCD1DirectoryFlag{g_emulator->m_sio->m_memoryCard[0].m_directoryFlag}, + SIOMCD1ChecksumIn{g_emulator->m_sio->m_memoryCard[0].m_checksumIn}, SIOMCD1ChecksumOut{g_emulator->m_sio->m_memoryCard[0].m_checksumOut}, SIOMCD1CommandTicks{g_emulator->m_sio->m_memoryCard[0].m_commandTicks}, SIOMCD1CurrentCommand{g_emulator->m_sio->m_memoryCard[0].m_currentCommand}, @@ -107,16 +106,26 @@ PCSX::SaveStates::SaveState PCSX::SaveStates::constructSaveState() { SIOMCD2Sector{g_emulator->m_sio->m_memoryCard[1].m_sector}, SIOMCD2DataOffset{g_emulator->m_sio->m_memoryCard[1].m_dataOffset}, }, - Hardware {}, - Counters {}, - MDEC {}, - PCdrvFilesField {}, - CallStacks {}, - CDRom { - CDParam { g_emulator->m_cdrom->m_param }, + Hardware{}, + Counters{}, + MDEC{}, + PCdrvFilesField{}, + CallStacks{}, + CDRom{ + CDDataFIFO{g_emulator->m_cdrom->m_dataFIFO}, + CDParamFIFO{g_emulator->m_cdrom->m_paramFIFO}, + CDResponseFIFO{g_emulator->m_cdrom->m_responseFIFO}, + CDDataFIFOIndex{g_emulator->m_cdrom->m_dataFIFOIndex}, + CDDataFIFOSize{g_emulator->m_cdrom->m_dataFIFOSize}, + CDParamFIFOSize{g_emulator->m_cdrom->m_paramFIFOSize}, + CDResponseFIFOData{g_emulator->m_cdrom->m_responseFIFOIndex}, + CDResponseFIFOSize{g_emulator->m_cdrom->m_responseFIFOSize}, + CDRegisterIndex{g_emulator->m_cdrom->m_registerIndex}, + CDBusy{g_emulator->m_cdrom->m_busy}, + CDState{g_emulator->m_cdrom->m_state}, + CDCommand{g_emulator->m_cdrom->m_command}, }, }; - // clang-format on } namespace PCSX { diff --git a/src/core/sstate.h b/src/core/sstate.h index 22802a3ea..663bffe11 100644 --- a/src/core/sstate.h +++ b/src/core/sstate.h @@ -221,6 +221,7 @@ typedef Protobuf::Field CallSP; typedef Protobuf::Field CallFP; typedef Protobuf::Field Shadow; typedef Protobuf::Message Call; + typedef Protobuf::RepeatedVariableField Calls; typedef Protobuf::Field LowSP; typedef Protobuf::Field HighSP; @@ -229,12 +230,28 @@ typedef Protobuf::Field PresumedFP; typedef Protobuf::Field CallstackIsCurrent; typedef Protobuf::Message CallStack; + typedef Protobuf::RepeatedVariableField CallStacksMessageField; typedef Protobuf::Field CallStacksCurrentSP; typedef Protobuf::Message CallStacks; typedef Protobuf::MessageField CallStacksField; -typedef Protobuf::FieldPtr, TYPESTRING("param"), 1> CDParam; -typedef Protobuf::Message CDRom; + +typedef Protobuf::FieldPtr, TYPESTRING("dataFIFO"), 1> CDDataFIFO; +typedef Protobuf::FieldPtr, TYPESTRING("paramFIFO"), 2> CDParamFIFO; +typedef Protobuf::FieldPtr, TYPESTRING("responseFIFO"), 3> CDResponseFIFO; +typedef Protobuf::FieldRef CDDataFIFOIndex; +typedef Protobuf::FieldRef CDDataFIFOSize; +typedef Protobuf::FieldRef CDParamFIFOSize; +typedef Protobuf::FieldRef CDResponseFIFOData; +typedef Protobuf::FieldRef CDResponseFIFOSize; +typedef Protobuf::FieldRef CDRegisterIndex; +typedef Protobuf::FieldRef CDBusy; +typedef Protobuf::FieldRef CDState; +typedef Protobuf::FieldRef CDCommand; +typedef Protobuf::Message + CDRom; typedef Protobuf::MessageField CDRomField; typedef Protobuf::Message Date: Wed, 14 Dec 2022 03:03:48 -0800 Subject: [PATCH 004/185] Bit more code here. --- src/core/cdrom.cc | 175 ++++++++++++++++++++++++++++++++++++++-------- src/core/cdrom.h | 12 ++++ 2 files changed, 159 insertions(+), 28 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index c15f9a943..85b34b8cf 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -37,7 +37,7 @@ class CDRomImpl final : public PCSX::CDRom { enum Commands { CdlSync = 0, CdlGetStat = 1, - CdlSetloc = 2, + CdlSetLoc = 2, CdlPlay = 3, CdlForward = 4, CdlBackward = 5, @@ -48,18 +48,18 @@ class CDRomImpl final : public PCSX::CDRom { CdlReset = 10, CdlMute = 11, CdlDemute = 12, - CdlSetfilter = 13, - CdlSetmode = 14, - CdlGetparam = 15, - CdlGetlocL = 16, - CdlGetlocP = 17, + CdlSetFilter = 13, + CdlSetMode = 14, + CdlGetParam = 15, + CdlGetLocL = 16, + CdlGetLocP = 17, CdlReadT = 18, CdlGetTN = 19, CdlGetTD = 20, CdlSeekL = 21, CdlSeekP = 22, - CdlSetclock = 23, - CdlGetclock = 24, + CdlSetClock = 23, + CdlGetClock = 24, CdlTest = 25, CdlID = 26, CdlReadS = 27, @@ -89,7 +89,7 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t v01 = m_registerIndex & 3; uint8_t adpcmPlaying = 0; uint8_t v3 = m_paramFIFOSize == 0 ? 0x08 : 0; - uint8_t v4 = m_paramFIFOSize == 16 ? 0x10 : 0; + uint8_t v4 = paramFIFOFull() ? 0x10 : 0; uint8_t v5 = responseFIFOEmpty() ? 0x20 : 0; uint8_t v6 = m_dataFIFOSize == m_dataFIFOIndex ? 0x40 : 0; uint8_t v7 = m_busy ? 0x80 : 0; @@ -107,37 +107,156 @@ class CDRomImpl final : public PCSX::CDRom { return m_dataFIFO[m_dataFIFOIndex++]; } - uint8_t read3() override { return 0; } + uint8_t read3() override { + switch (m_registerIndex & 1) { + case 0: { + // cause mask + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom r0:0 not available yet\n"); + PCSX::g_system->pause(); + return 0; + } break; + case 1: { + // cause + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom r0:1 not available yet\n"); + PCSX::g_system->pause(); + return 0; + } break; + } + // should not be reachable + return 0; + } - void write0(uint8_t rt) override { m_registerIndex = rt & 3; } + void write0(uint8_t value) override { m_registerIndex = value & 3; } - void write1(uint8_t rt) override { + void write1(uint8_t value) override { switch (m_registerIndex) { case 0: { if (m_busy) { // The CD-Rom controller is already executing a command. - // This basically results in undefined behavior. - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom command while controller is busy"); + // This basically results in undefined behavior. We'll still + // have to address this, as some games will do it anyway. + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom command while controller is busy\n"); PCSX::g_system->pause(); } - m_busy = true; - m_command = rt; - if (PCSX::g_emulator->settings.get() - .get()) { - logCDROM(rt); - } - startCommand(rt); + startCommand(value); + } break; + case 1: { + // ?? + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w1:1 not available yet\n"); + PCSX::g_system->pause(); + } break; + case 2: { + // ?? + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w1:2 not available yet\n"); + PCSX::g_system->pause(); + } break; + case 3: { + // Volume setting RR + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w1:3 not available yet\n"); + PCSX::g_system->pause(); } break; } } - void write2(uint8_t rt) override {} + void write2(uint8_t value) override { + switch (m_registerIndex) { + case 0: { + if (!paramFIFOFull()) m_paramFIFO[m_paramFIFOSize++] = value; + } break; + case 1: { + // cause mask + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w2:1 not available yet\n"); + PCSX::g_system->pause(); + } break; + case 2: { + // Volume setting LL + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w2:2 not available yet\n"); + PCSX::g_system->pause(); + } break; + case 3: { + // Volume setting RL + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w2:3 not available yet\n"); + PCSX::g_system->pause(); + } break; + } + } - void write3(uint8_t rt) override {} + void write3(uint8_t value) override { + switch (m_registerIndex) { + case 0: { + // ?? + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:0 not available yet\n"); + PCSX::g_system->pause(); + } break; + case 1: { + // cause ack + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:1 not available yet\n"); + PCSX::g_system->pause(); + } break; + case 2: { + // Volume setting LR + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:2 not available yet\n"); + PCSX::g_system->pause(); + } break; + case 3: { + // SPU settings latch + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:3 not available yet\n"); + PCSX::g_system->pause(); + } break; + } + } + + void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom DMA not available yet\n"); + PCSX::g_system->pause(); + } + + void startCommand(uint8_t command) { + m_busy = true; + m_command = command; + if (PCSX::g_emulator->settings.get() + .get()) { + logCDROM(command); + } + + if (command > 30) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "Unknown CD-Rom command\n"); + PCSX::g_system->pause(); + } - void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override {} + auto handler = c_commandsHandlers[command]; + + (this->*handler)(); + } - void startCommand(uint8_t command) {} + void cdlUnimplemented() { + PCSX::g_system->log(PCSX::LogClass::CDROM, "Unknown CD-Rom command\n"); + PCSX::g_system->pause(); + } + + typedef void(CDRomImpl::*CommandType)(); + + const CommandType c_commandsHandlers[31] { +#if 0 + &CDRomImpl::cdlSync, &CDRomImpl::cdlGetStat, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlPlay, // 0 + &CDRomImpl::cdlForward, &CDRomImpl::cdlBackward, &CDRomImpl::cdlReadN, &CDRomImpl::cdlStandby, // 4 + &CDRomImpl::cdlStop, &CDRomImpl::cdlPause, &CDRomImpl::cdlReset, &CDRomImpl::cdlMute, // 8 + &CDRomImpl::cdlDemute, &CDRomImpl::cdlSetFilter, &CDRomImpl::cdlSetMode, &CDRomImpl::cdlGetParam, // 12 + &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, &CDRomImpl::cdlReadT, &CDRomImpl::cdlGetTN, // 16 + &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, &CDRomImpl::cdlSetClock, // 20 + &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 + &CDRomImpl::cdlInit, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 +#else + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 0 + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 4 + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 8 + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 12 + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 16 + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 20 + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 24 + &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 28 +#endif + }; void logCDROM(uint8_t command) { uint32_t pc = PCSX::g_emulator->m_cpu->m_regs.pc; @@ -146,18 +265,18 @@ class CDRomImpl final : public PCSX::CDRom { case CdlTest: PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlTest %02x\n", pc, m_paramFIFO[0]); break; - case CdlSetloc: + case CdlSetLoc: PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetloc %02x:%02x:%02x\n", pc, m_paramFIFO[0], m_paramFIFO[1], m_paramFIFO[2]); break; case CdlPlay: PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlPlay %i\n", pc, m_paramFIFO[0]); break; - case CdlSetfilter: + case CdlSetFilter: PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetfilter file: %i, channel: %i\n", pc, m_paramFIFO[0], m_paramFIFO[1]); break; - case CdlSetmode: { + case CdlSetMode: { auto mode = m_paramFIFO[0]; std::string modeDecode = mode & 1 ? "CDDA" : "DATA"; if (mode & 2) modeDecode += " Autopause"; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index c32d446bd..7b9d1d117 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -86,6 +86,7 @@ class CDRom { friend SaveStates::SaveState SaveStates::constructSaveState(); bool dataFIFOEmpty() { return m_dataFIFOIndex == m_dataFIFOSize; } + bool paramFIFOFull() { return m_paramFIFOSize == 16; } bool responseFIFOEmpty() { return m_responseFIFOIndex == m_responseFIFOSize; } uint8_t m_dataFIFO[2352] = {0}; @@ -101,6 +102,17 @@ class CDRom { uint8_t m_state = 0; uint8_t m_command = 0; + // to save/init + enum class Cause : uint8_t { + None = 0, + DataReady = 1, + Complete = 2, + Acknowledge = 3, + End = 4, + Error = 5, + }; + Cause m_cause = Cause::None; + private: friend class Widgets::IsoBrowser; std::string m_cdromId; From ed7b6685921456d5d77ca28df0f26403ea434044 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 19 Dec 2022 22:48:22 -0800 Subject: [PATCH 005/185] Advancing in the new CD-Rom code. --- src/core/cdrom.cc | 177 +++++++++++++++++++++++++++++++++------------- src/core/cdrom.h | 4 +- 2 files changed, 130 insertions(+), 51 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 85b34b8cf..26e0050cc 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -82,132 +82,183 @@ class CDRomImpl final : public PCSX::CDRom { m_command = 0; } - void interrupt() override {} + void interrupt() override { + auto handler = c_commandsHandlers[m_command]; + + (this->*handler)(); + } + void dmaInterrupt() override {} + void schedule(uint32_t cycles) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: scheduling callback in %d cycles\n", cycles); + PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDR, cycles); + } + + void scheduleDMA(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRDMA, cycles); } + + void triggerIRQ() { psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); } + + void clearIRQ() { psxHu32ref(0x1070) &= SWAP_LE32(~uint32_t(4)); } + uint8_t read0() override { uint8_t v01 = m_registerIndex & 3; uint8_t adpcmPlaying = 0; uint8_t v3 = m_paramFIFOSize == 0 ? 0x08 : 0; - uint8_t v4 = paramFIFOFull() ? 0x10 : 0; - uint8_t v5 = responseFIFOEmpty() ? 0x20 : 0; - uint8_t v6 = m_dataFIFOSize == m_dataFIFOIndex ? 0x40 : 0; + uint8_t v4 = paramFIFOAvailable() ? 0x10 : 0; + uint8_t v5 = responseFIFOHasData() ? 0x20 : 0; + uint8_t v6 = m_dataFIFOSize != m_dataFIFOIndex ? 0x40 : 0; uint8_t v7 = m_busy ? 0x80 : 0; - return v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7; + uint8_t ret = v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7; + + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r0: %02x\n", ret); + return ret; } uint8_t read1() override { - if (responseFIFOEmpty()) return 0; - return m_responseFIFO[m_responseFIFOIndex++]; + uint8_t ret = 0; + if (!responseFIFOHasData()) { + ret = 0; + } else { + ret = m_responseFIFO[m_responseFIFOIndex++]; + } + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r1: %02x\n", ret); + return ret; } uint8_t read2() override { - if (dataFIFOEmpty()) return 0; - return m_dataFIFO[m_dataFIFOIndex++]; + uint8_t ret = 0; + if (dataFIFOEmpty()) { + ret = 0; + } else { + ret = m_dataFIFO[m_dataFIFOIndex++]; + } + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r2: %02x\n", ret); + return ret; } uint8_t read3() override { switch (m_registerIndex & 1) { case 0: { // cause mask - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom r0:0 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r3:0 not available yet\n"); PCSX::g_system->pause(); return 0; } break; case 1: { // cause - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom r0:1 not available yet\n"); - PCSX::g_system->pause(); - return 0; + // TODO: add bit 4 + return magic_enum::enum_integer(m_cause) | 0xe0; } break; } // should not be reachable return 0; } - void write0(uint8_t value) override { m_registerIndex = value & 3; } + void write0(uint8_t value) override { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w0: %02x\n", value); + m_registerIndex = value & 3; + } void write1(uint8_t value) override { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1: %02x\n", value); switch (m_registerIndex) { case 0: { if (m_busy) { // The CD-Rom controller is already executing a command. // This basically results in undefined behavior. We'll still // have to address this, as some games will do it anyway. - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom command while controller is busy\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: command while controller is busy\n"); PCSX::g_system->pause(); } startCommand(value); } break; case 1: { // ?? - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w1:1 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:1 not available yet\n"); PCSX::g_system->pause(); } break; case 2: { // ?? - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w1:2 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:2 not available yet\n"); PCSX::g_system->pause(); } break; case 3: { // Volume setting RR - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w1:3 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:3 not available yet\n"); PCSX::g_system->pause(); } break; } } void write2(uint8_t value) override { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2: %02x\n", value); switch (m_registerIndex) { case 0: { - if (!paramFIFOFull()) m_paramFIFO[m_paramFIFOSize++] = value; + if (paramFIFOAvailable()) m_paramFIFO[m_paramFIFOSize++] = value; } break; case 1: { // cause mask - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w2:1 not available yet\n"); + if (value == 0x1f) { + // all enabled? + // TODO: act on this? + return; + } + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:1 not available yet\n"); PCSX::g_system->pause(); } break; case 2: { // Volume setting LL - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w2:2 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:2 not available yet\n"); PCSX::g_system->pause(); } break; case 3: { // Volume setting RL - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w2:3 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:3 not available yet\n"); PCSX::g_system->pause(); } break; } } void write3(uint8_t value) override { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3: %02x\n", value); switch (m_registerIndex) { case 0: { // ?? - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:0 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:0 not available yet\n"); PCSX::g_system->pause(); } break; case 1: { // cause ack - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:1 not available yet\n"); + if (value == 0x07) { + // partial ack? + // TODO: act on this? + return; + } + if (value == 0x1f) { + // all ack? + // TODO: act on this? + return; + } + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:1 not available yet\n"); PCSX::g_system->pause(); } break; case 2: { // Volume setting LR - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:2 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:2 not available yet\n"); PCSX::g_system->pause(); } break; case 3: { // SPU settings latch - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom w3:3 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:3 not available yet\n"); PCSX::g_system->pause(); } break; } } void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom DMA not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: DMA not available yet\n"); PCSX::g_system->pause(); } @@ -220,7 +271,7 @@ class CDRomImpl final : public PCSX::CDRom { } if (command > 30) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "Unknown CD-Rom command\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command\n"); PCSX::g_system->pause(); } @@ -229,12 +280,38 @@ class CDRomImpl final : public PCSX::CDRom { (this->*handler)(); } - void cdlUnimplemented() { - PCSX::g_system->log(PCSX::LogClass::CDROM, "Unknown CD-Rom command\n"); + // Command 10. + void cdlReset() { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlReset, state = %i\n", m_state); + switch (m_state) { + case 0: + // TODO: figure out exactly the various states of the CD-Rom controller + // that are being reset, and their value. Also figure out proper timings. + m_state = 1; + schedule(5'000); + break; + case 1: + m_cause = Cause::Acknowledge; + m_state = 2; + triggerIRQ(); + schedule(5'000); + break; + case 2: + m_cause = Cause::Complete; + m_state = 0; + triggerIRQ(); + m_busy = false; + m_command = 0; + break; + } + } + + void cdlUnk() { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command\n"); PCSX::g_system->pause(); } - typedef void(CDRomImpl::*CommandType)(); + typedef void (CDRomImpl::*CommandType)(); const CommandType c_commandsHandlers[31] { #if 0 @@ -247,14 +324,14 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 &CDRomImpl::cdlInit, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 #else - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 0 - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 4 - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 8 - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 12 - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 16 - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 20 - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 24 - &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, &CDRomImpl::cdlUnimplemented, // 28 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 0 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlReset, &CDRomImpl::cdlUnk, // 8 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 16 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 28 #endif }; @@ -263,18 +340,19 @@ class CDRomImpl final : public PCSX::CDRom { switch (command & 0xff) { case CdlTest: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlTest %02x\n", pc, m_paramFIFO[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlTest %02x\n", pc, m_paramFIFO[0]); break; case CdlSetLoc: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetloc %02x:%02x:%02x\n", pc, + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlSetloc %02x:%02x:%02x\n", pc, m_paramFIFO[0], m_paramFIFO[1], m_paramFIFO[2]); break; case CdlPlay: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlPlay %i\n", pc, m_paramFIFO[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlPlay %i\n", pc, m_paramFIFO[0]); break; case CdlSetFilter: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetfilter file: %i, channel: %i\n", - pc, m_paramFIFO[0], m_paramFIFO[1]); + PCSX::g_system->log(PCSX::LogClass::CDROM, + "CD-Rom: %08x] Command: CdlSetfilter file: %i, channel: %i\n", pc, m_paramFIFO[0], + m_paramFIFO[1]); break; case CdlSetMode: { auto mode = m_paramFIFO[0]; @@ -298,25 +376,25 @@ class CDRomImpl final : public PCSX::CDRom { } if (mode & 0x40) modeDecode += " RealTimePlay"; modeDecode += mode & 0x80 ? " @2x" : " @1x"; - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlSetmode %02x (%s)\n", pc, + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlSetmode %02x (%s)\n", pc, m_paramFIFO[0], modeDecode); } break; case CdlGetTN: - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlGetTN (returns %i)\n", pc, + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlGetTN (returns %i)\n", pc, m_iso->getTN()); break; case CdlGetTD: { auto ret = m_iso->getTD(m_paramFIFO[0]); PCSX::g_system->log(PCSX::LogClass::CDROM, - "%08x [CDROM] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", pc, m_paramFIFO[0], + "CD-Rom: %08x] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", pc, m_paramFIFO[0], ret.m, ret.s, ret.f); } break; default: if ((command & 0xff) > c_cdCmdEnumCount) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: CdlUnknown(0x%02X)\n", pc, + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlUnknown(0x%02X)\n", pc, command & 0xff); } else { - PCSX::g_system->log(PCSX::LogClass::CDROM, "%08x [CDROM] Command: %s\n", pc, + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: %s\n", pc, magic_enum::enum_names()[command & 0xff]); } break; @@ -327,6 +405,7 @@ class CDRomImpl final : public PCSX::CDRom { } // namespace PCSX::CDRom *PCSX::CDRom::factory() { return new CDRomImpl; } + void PCSX::CDRom::parseIso() { m_cdromId.clear(); m_cdromLabel.clear(); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 7b9d1d117..e49ae6a4a 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -86,8 +86,8 @@ class CDRom { friend SaveStates::SaveState SaveStates::constructSaveState(); bool dataFIFOEmpty() { return m_dataFIFOIndex == m_dataFIFOSize; } - bool paramFIFOFull() { return m_paramFIFOSize == 16; } - bool responseFIFOEmpty() { return m_responseFIFOIndex == m_responseFIFOSize; } + bool paramFIFOAvailable() { return m_paramFIFOSize != 16; } + bool responseFIFOHasData() { return m_responseFIFOIndex == m_responseFIFOSize; } uint8_t m_dataFIFO[2352] = {0}; uint8_t m_paramFIFO[16] = {0}; From 9d818e634abab56895a29c7110ade4de3065f53a Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 19 Dec 2022 23:29:54 -0800 Subject: [PATCH 006/185] Adding cdlSetLoc. --- src/core/cdrom.cc | 44 ++++++++++++++++++++++++++++++++++++++++++-- src/core/cdrom.h | 5 ++++- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 26e0050cc..6be545cb4 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -23,6 +23,7 @@ #include "core/cdrom.h" +#include "cdrom/iec-60908b.h" #include "cdrom/iso9660-reader.h" #include "core/debug.h" #include "core/psxdma.h" @@ -69,6 +70,18 @@ class CDRomImpl final : public PCSX::CDRom { }; static constexpr size_t c_cdCmdEnumCount = magic_enum::enum_count(); + static constexpr bool isValidBCD(uint8_t value) { return (value & 0x0f) <= 9 && (value & 0xf0) <= 0x90; } + static constexpr std::optional getMSF(uint8_t *msf) { + bool validBCD = isValidBCD(msf[0]) && isValidBCD(msf[1]) && isValidBCD(msf[2]); + if (!validBCD) return {}; + uint8_t m = PCSX::IEC60908b::btoi(msf[0]); + uint8_t s = PCSX::IEC60908b::btoi(msf[1]); + uint8_t f = PCSX::IEC60908b::btoi(msf[2]); + + if (s >= 60) return {}; + if (f >= 75) return {}; + return PCSX::IEC60908b::MSF(m, s, f); + } void reset() override { m_dataFIFOIndex = 0; @@ -280,6 +293,32 @@ class CDRomImpl final : public PCSX::CDRom { (this->*handler)(); } + // Command 2. + void cdlSetLoc() { + switch (m_state) { + case 0: + // TODO: Figure out proper timings. + m_state = 1; + schedule(5'000); + break; + case 1: { + // TODO: Verify that the command is aborted if + // these parameters are indeed wrong. + auto maybeMSF = getMSF(m_paramFIFO); + if ((m_paramFIFOSize == 3) && (maybeMSF.has_value())) { + m_cause = Cause::Acknowledge; + m_seekPosition = maybeMSF.value(); + } else { + m_cause = Cause::Error; + } + m_state = 0; + m_busy = false; + m_command = 0; + triggerIRQ(); + } break; + } + } + // Command 10. void cdlReset() { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlReset, state = %i\n", m_state); @@ -294,14 +333,15 @@ class CDRomImpl final : public PCSX::CDRom { m_cause = Cause::Acknowledge; m_state = 2; triggerIRQ(); + // TODO: should we wait for ack first? schedule(5'000); break; case 2: m_cause = Cause::Complete; m_state = 0; - triggerIRQ(); m_busy = false; m_command = 0; + triggerIRQ(); break; } } @@ -324,7 +364,7 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 &CDRomImpl::cdlInit, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 #else - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 0 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlReset, &CDRomImpl::cdlUnk, // 8 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 diff --git a/src/core/cdrom.h b/src/core/cdrom.h index e49ae6a4a..3e9f7de2a 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -89,6 +89,7 @@ class CDRom { bool paramFIFOAvailable() { return m_paramFIFOSize != 16; } bool responseFIFOHasData() { return m_responseFIFOIndex == m_responseFIFOSize; } + // to save/init uint8_t m_dataFIFO[2352] = {0}; uint8_t m_paramFIFO[16] = {0}; uint8_t m_responseFIFO[16] = {0}; @@ -102,7 +103,6 @@ class CDRom { uint8_t m_state = 0; uint8_t m_command = 0; - // to save/init enum class Cause : uint8_t { None = 0, DataReady = 1, @@ -113,6 +113,9 @@ class CDRom { }; Cause m_cause = Cause::None; + IEC60908b::MSF m_currentPosition; + IEC60908b::MSF m_seekPosition; + private: friend class Widgets::IsoBrowser; std::string m_cdromId; From 43159ab16cdcb28141c172e81c1f1aef758bc598 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 20 Dec 2022 21:59:55 -0800 Subject: [PATCH 007/185] General cleanup. --- src/core/gte.cc | 4 +-- src/core/psxinterpreter.cc | 68 +++++++++++++++++++------------------- src/core/r3000a.h | 21 ++---------- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/src/core/gte.cc b/src/core/gte.cc index cf9799466..0410d26f4 100644 --- a/src/core/gte.cc +++ b/src/core/gte.cc @@ -446,9 +446,9 @@ static int32_t Lm_D(int64_t a, int sf) { return LIM(gte_shift(a, sf), 0xffff, 0x int64_t PCSX::GTE::F(int64_t a) { s_mac0 = a; - if (a > S64(0x7fffffff)) FLAG |= (1 << 31) | (1 << 16); + if (a > 0x7fffffffLL) FLAG |= (1 << 31) | (1 << 16); - if (a < S64(-0x80000000)) FLAG |= (1 << 31) | (1 << 15); + if (a < -0x80000000LL) FLAG |= (1 << 31) | (1 << 15); return a; } diff --git a/src/core/psxinterpreter.cc b/src/core/psxinterpreter.cc index 751ef5a58..04e02cb27 100644 --- a/src/core/psxinterpreter.cc +++ b/src/core/psxinterpreter.cc @@ -372,7 +372,7 @@ void InterpretedCPU::psxADDI(uint32_t code) { void InterpretedCPU::psxADDIU(uint32_t code) { if (!_Rt_) return; maybeCancelDelayedLoad(_Rt_); - uint32_t newValue = _u32(_rRs_) + _Imm_; + uint32_t newValue = _rRs_ + _Imm_; if (_Rt_ == 29) { if (_Rs_ == 29) { PCSX::g_emulator->m_callStacks->offsetSP(_rRt_, _Imm_); @@ -386,7 +386,7 @@ void InterpretedCPU::psxADDIU(uint32_t code) { void InterpretedCPU::psxANDI(uint32_t code) { if (!_Rt_) return; maybeCancelDelayedLoad(_Rt_); - uint32_t newValue = _u32(_rRs_) & _ImmU_; + uint32_t newValue = _rRs_ & _ImmU_; if (_Rt_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRt_, newValue); } @@ -395,7 +395,7 @@ void InterpretedCPU::psxANDI(uint32_t code) { void InterpretedCPU::psxORI(uint32_t code) { if (!_Rt_) return; maybeCancelDelayedLoad(_Rt_); - uint32_t newValue = _u32(_rRs_) | _ImmU_; + uint32_t newValue = _rRs_ | _ImmU_; if (_Rt_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRt_, newValue); } @@ -404,7 +404,7 @@ void InterpretedCPU::psxORI(uint32_t code) { void InterpretedCPU::psxXORI(uint32_t code) { if (!_Rt_) return; maybeCancelDelayedLoad(_Rt_); - uint32_t newValue = _u32(_rRs_) ^ _ImmU_; + uint32_t newValue = _rRs_ ^ _ImmU_; if (_Rt_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRt_, newValue); } @@ -413,7 +413,7 @@ void InterpretedCPU::psxXORI(uint32_t code) { void InterpretedCPU::psxSLTI(uint32_t code) { if (!_Rt_) return; maybeCancelDelayedLoad(_Rt_); - uint32_t newValue = _i32(_rRs_) < _Imm_; + uint32_t newValue = int32_t(_rRs_) < _Imm_; if (_Rt_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRt_, newValue); } @@ -422,7 +422,7 @@ void InterpretedCPU::psxSLTI(uint32_t code) { void InterpretedCPU::psxSLTIU(uint32_t code) { if (!_Rt_) return; maybeCancelDelayedLoad(_Rt_); - uint32_t newValue = _u32(_rRs_) < ((uint32_t)_Imm_); + uint32_t newValue = _rRs_ < ((uint32_t)_Imm_); if (_Rt_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRt_, newValue); } @@ -519,7 +519,7 @@ void InterpretedCPU::psxSUBU(uint32_t code) { void InterpretedCPU::psxAND(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRs_) & _u32(_rRt_); + uint32_t newValue = _rRs_ & _rRt_; if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -528,7 +528,7 @@ void InterpretedCPU::psxAND(uint32_t code) { void InterpretedCPU::psxOR(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRs_) | _u32(_rRt_); + uint32_t newValue = _rRs_ | _rRt_; if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -537,7 +537,7 @@ void InterpretedCPU::psxOR(uint32_t code) { void InterpretedCPU::psxXOR(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRs_) ^ _u32(_rRt_); + uint32_t newValue = _rRs_ ^ _rRt_; if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -546,7 +546,7 @@ void InterpretedCPU::psxXOR(uint32_t code) { void InterpretedCPU::psxNOR(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = ~(_u32(_rRs_) | _u32(_rRt_)); + uint32_t newValue = ~(_rRs_ | _rRt_); if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -555,7 +555,7 @@ void InterpretedCPU::psxNOR(uint32_t code) { void InterpretedCPU::psxSLT(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _i32(_rRs_) < _i32(_rRt_); + uint32_t newValue = int32_t(_rRs_) < int32_t(_rRt_); if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -564,7 +564,7 @@ void InterpretedCPU::psxSLT(uint32_t code) { void InterpretedCPU::psxSLTU(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRs_) < _u32(_rRt_); + uint32_t newValue = _rRs_ < _rRt_; if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -621,7 +621,7 @@ void InterpretedCPU::psxMULTU(uint32_t code) { * Format: OP rs, offset * *********************************************************/ #define RepZBranchi32(op) \ - if (_i32(_rRs_) op 0) { \ + if (int32_t(_rRs_) op 0) { \ doBranch(_BranchTarget_, false); \ } #define RepZBranchLinki32(op) \ @@ -649,7 +649,7 @@ void InterpretedCPU::psxBLTZAL(uint32_t code) { RepZBranchLinki32(<); } // Bra void InterpretedCPU::psxSLL(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRt_) << _Sa_; + uint32_t newValue = _rRt_ << _Sa_; if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -658,7 +658,7 @@ void InterpretedCPU::psxSLL(uint32_t code) { void InterpretedCPU::psxSRA(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _i32(_rRt_) >> _Sa_; + uint32_t newValue = int32_t(_rRt_) >> _Sa_; if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -667,7 +667,7 @@ void InterpretedCPU::psxSRA(uint32_t code) { void InterpretedCPU::psxSRL(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRt_) >> _Sa_; + uint32_t newValue = _rRt_ >> _Sa_; if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -681,7 +681,7 @@ void InterpretedCPU::psxSRL(uint32_t code) { void InterpretedCPU::psxSLLV(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRt_) << (_u32(_rRs_) & 0x1f); + uint32_t newValue = _rRt_ << (_rRs_ & 0x1f); if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -690,7 +690,7 @@ void InterpretedCPU::psxSLLV(uint32_t code) { void InterpretedCPU::psxSRAV(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _i32(_rRt_) >> (_u32(_rRs_) & 0x1f); + uint32_t newValue = int32_t(_rRt_) >> (_rRs_ & 0x1f); if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -699,7 +699,7 @@ void InterpretedCPU::psxSRAV(uint32_t code) { void InterpretedCPU::psxSRLV(uint32_t code) { if (!_Rd_) return; maybeCancelDelayedLoad(_Rd_); - uint32_t newValue = _u32(_rRt_) >> (_u32(_rRs_) & 0x1f); + uint32_t newValue = _rRt_ >> (_rRs_ & 0x1f); if (_Rd_ == 29) { PCSX::g_emulator->m_callStacks->setSP(_rRd_, newValue); } @@ -823,7 +823,7 @@ void InterpretedCPU::psxJR(uint32_t code) { } void InterpretedCPU::psxJALR(uint32_t code) { - uint32_t temp = _u32(_rRs_); + uint32_t temp = _rRs_; if (_Rd_) { maybeCancelDelayedLoad(_Rd_); uint32_t ra = m_regs.pc + 4; @@ -852,12 +852,12 @@ void InterpretedCPU::psxJALR(uint32_t code) { * Format: OP rt, offset(base) * *********************************************************/ -#define _oB_ (_u32(_rRs_) + _Imm_) +#define _oB_ (_rRs_ + _Imm_) void InterpretedCPU::psxLB(uint32_t code) { // load delay = 1 latency if (_Rt_) { - _i32(delayedLoadRef(_Rt_)) = (int8_t)PCSX::g_emulator->m_mem->read8(_oB_); + delayedLoadRef(_Rt_) = (int8_t)PCSX::g_emulator->m_mem->read8(_oB_); } else { PCSX::g_emulator->m_mem->read8(_oB_); } @@ -866,7 +866,7 @@ void InterpretedCPU::psxLB(uint32_t code) { void InterpretedCPU::psxLBU(uint32_t code) { // load delay = 1 latency if (_Rt_) { - _u32(delayedLoadRef(_Rt_)) = PCSX::g_emulator->m_mem->read8(_oB_); + delayedLoadRef(_Rt_) = PCSX::g_emulator->m_mem->read8(_oB_); } else { PCSX::g_emulator->m_mem->read8(_oB_); } @@ -883,7 +883,7 @@ void InterpretedCPU::psxLH(uint32_t code) { } if (_Rt_) { - _i32(delayedLoadRef(_Rt_)) = (short)PCSX::g_emulator->m_mem->read16(_oB_); + delayedLoadRef(_Rt_) = (short)PCSX::g_emulator->m_mem->read16(_oB_); } else { PCSX::g_emulator->m_mem->read16(_oB_); } @@ -900,7 +900,7 @@ void InterpretedCPU::psxLHU(uint32_t code) { } if (_Rt_) { - _u32(delayedLoadRef(_Rt_)) = PCSX::g_emulator->m_mem->read16(_oB_); + delayedLoadRef(_Rt_) = PCSX::g_emulator->m_mem->read16(_oB_); } else { PCSX::g_emulator->m_mem->read16(_oB_); } @@ -928,7 +928,7 @@ void InterpretedCPU::psxLW(uint32_t code) { } break; } - _u32(delayedLoadRef(_Rt_)) = val; + delayedLoadRef(_Rt_) = val; } } @@ -939,7 +939,7 @@ void InterpretedCPU::psxLWL(uint32_t code) { // load delay = 1 latency if (!_Rt_) return; - _u32(delayedLoadRef(_Rt_, LWL_MASK[shift])) = mem << LWL_SHIFT[shift]; + delayedLoadRef(_Rt_, LWL_MASK[shift]) = mem << LWL_SHIFT[shift]; /* Mem = 1234. Reg = abcd @@ -957,7 +957,7 @@ void InterpretedCPU::psxLWR(uint32_t code) { // load delay = 1 latency if (!_Rt_) return; - _u32(delayedLoadRef(_Rt_, LWR_MASK[shift])) = mem >> LWR_SHIFT[shift]; + delayedLoadRef(_Rt_, LWR_MASK[shift]) = mem >> LWR_SHIFT[shift]; /* Mem = 1234. Reg = abcd @@ -999,7 +999,7 @@ void InterpretedCPU::psxSWL(uint32_t code) { uint32_t shift = addr & 3; uint32_t mem = PCSX::g_emulator->m_mem->read32(addr & ~3); - PCSX::g_emulator->m_mem->write32(addr & ~3, (_u32(_rRt_) >> SWL_SHIFT[shift]) | (mem & SWL_MASK[shift])); + PCSX::g_emulator->m_mem->write32(addr & ~3, (_rRt_ >> SWL_SHIFT[shift]) | (mem & SWL_MASK[shift])); /* Mem = 1234. Reg = abcd 0 123a (reg >> 24) | (mem & 0xffffff00) @@ -1014,7 +1014,7 @@ void InterpretedCPU::psxSWR(uint32_t code) { uint32_t shift = addr & 3; uint32_t mem = PCSX::g_emulator->m_mem->read32(addr & ~3); - PCSX::g_emulator->m_mem->write32(addr & ~3, (_u32(_rRt_) << SWR_SHIFT[shift]) | (mem & SWR_MASK[shift])); + PCSX::g_emulator->m_mem->write32(addr & ~3, (_rRt_ << SWR_SHIFT[shift]) | (mem & SWR_MASK[shift])); /* Mem = 1234. Reg = abcd @@ -1032,13 +1032,13 @@ void InterpretedCPU::psxSWR(uint32_t code) { void InterpretedCPU::psxMFC0(uint32_t code) { // load delay = 1 latency if (!_Rt_) return; - _i32(delayedLoadRef(_Rt_)) = (int)m_regs.CP0.r[_Rd_]; + delayedLoadRef(_Rt_) = (int)m_regs.CP0.r[_Rd_]; } void InterpretedCPU::psxCFC0(uint32_t code) { // load delay = 1 latency if (!_Rt_) return; - _i32(delayedLoadRef(_Rt_)) = (int)m_regs.CP0.r[_Rd_]; + delayedLoadRef(_Rt_) = (int)m_regs.CP0.r[_Rd_]; } void InterpretedCPU::psxTestSWInts() { @@ -1070,8 +1070,8 @@ inline void InterpretedCPU::MTC0(int reg, uint32_t val) { } } -void InterpretedCPU::psxMTC0(uint32_t code) { MTC0(_Rd_, _u32(_rRt_)); } -void InterpretedCPU::psxCTC0(uint32_t code) { MTC0(_Rd_, _u32(_rRt_)); } +void InterpretedCPU::psxMTC0(uint32_t code) { MTC0(_Rd_, _rRt_); } +void InterpretedCPU::psxCTC0(uint32_t code) { MTC0(_Rd_, _rRt_); } void InterpretedCPU::psxMFC2(uint32_t code) { // load delay = 1 latency diff --git a/src/core/r3000a.h b/src/core/r3000a.h index 7064c681d..cac4a39ff 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -202,22 +202,6 @@ struct psxRegisters { uint8_t ICache_Code[0x1000]; }; -// U64 and S64 are used to wrap long integer constants. -#define U64(val) val##ULL -#define S64(val) val##LL - -#if defined(__BIGENDIAN__) - -#define _i32(x) reinterpret_cast(&x)[0] -#define _u32(x) reinterpret_cast(&x)[0] - -#else - -#define _i32(x) reinterpret_cast(&x)[0] -#define _u32(x) reinterpret_cast(&x)[0] - -#endif - // R3000A Instruction Macros #define _PC_ PCSX::g_emulator->m_cpu->m_regs.pc // The next PC to be executed @@ -337,13 +321,14 @@ class R3000Acpu { bool fromLink = false; } m_delayedLoadInfo[2]; unsigned m_currentDelayedLoad = 0; - uint32_t &delayedLoadRef(unsigned reg, uint32_t mask = 0) { + template + T &delayedLoadRef(unsigned reg, uint32_t mask = 0) { if (reg >= 32) abort(); auto &delayedLoad = m_delayedLoadInfo[m_currentDelayedLoad]; delayedLoad.active = true; delayedLoad.index = reg; delayedLoad.mask = mask; - return delayedLoad.value; + return reinterpret_cast(delayedLoad.value); } void delayedLoad(unsigned reg, uint32_t value, uint32_t mask = 0) { auto &ref = delayedLoadRef(reg, mask); From e5f56dc7abd1fe8651d0a7ec4a7d4c5f28442ea6 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 20 Dec 2022 22:00:52 -0800 Subject: [PATCH 008/185] Adding lid code. --- src/core/cdrom.cc | 11 +++++++++++ src/core/cdrom.h | 20 +++++++++++++++++++- src/core/psxemulator.h | 2 +- src/core/r3000a.h | 8 ++++++++ src/gui/gui.cc | 6 +++--- 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 6be545cb4..9971fbcd6 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -494,3 +494,14 @@ void PCSX::CDRom::parseIso() { g_system->printf(_("CD-ROM ID: %.9s\n"), m_cdromId); g_system->printf(_("CD-ROM EXE Name: %.255s\n"), exename); } + +bool PCSX::CDRom::isLidOpened() { + if (m_lidCloseScheduled) { + const uint32_t cycle = g_emulator->m_cpu->m_regs.cycle; + if (((int32_t)(m_lidCloseAtCycles - cycle)) <= 0) { + m_lidCloseScheduled = false; + m_lidOpened = false; + } + } + return m_lidOpened; +} diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 3e9f7de2a..958b70df0 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -50,7 +50,21 @@ class CDRom { CDRom() : m_iso(new CDRIso()) {} virtual ~CDRom() {} static CDRom* factory(); - bool isLidOpened() { return false; } + bool isLidOpened(); + void closeLid() { + m_lidOpened = false; + m_lidCloseScheduled = false; + } + void openLid() { + m_lidOpened = true; + m_lidCloseScheduled = false; + } + void scheduleCloseLid() { + m_lidOpened = true; + m_lidCloseScheduled = true; + using namespace std::chrono_literals; + m_lidCloseAtCycles = g_emulator->m_cpu->m_regs.getFutureCycle(1s); + } void parseIso(); std::shared_ptr getIso() { return m_iso; } @@ -89,6 +103,10 @@ class CDRom { bool paramFIFOAvailable() { return m_paramFIFOSize != 16; } bool responseFIFOHasData() { return m_responseFIFOIndex == m_responseFIFOSize; } + bool m_lidOpened = false; + bool m_lidCloseScheduled = false; + uint32_t m_lidCloseAtCycles = 0; + // to save/init uint8_t m_dataFIFO[2352] = {0}; uint8_t m_paramFIFO[16] = {0}; diff --git a/src/core/psxemulator.h b/src/core/psxemulator.h index c105de991..d77176eac 100644 --- a/src/core/psxemulator.h +++ b/src/core/psxemulator.h @@ -219,7 +219,7 @@ class Emulator { // Make the timing events trigger faster as we are currently assuming everything // takes one cycle, which is not the case on real hardware. // FIXME: Count the proper cycle and get rid of this - uint32_t m_psxClockSpeed = 33868800 /* 33.8688 MHz */; + static constexpr uint32_t m_psxClockSpeed = 33868800 /* 33.8688 MHz */; enum { BIAS = 2 }; int init(); diff --git a/src/core/r3000a.h b/src/core/r3000a.h index cac4a39ff..e1145b100 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -200,6 +201,13 @@ struct psxRegisters { uint32_t lowestTarget; uint8_t ICache_Addr[0x1000]; uint8_t ICache_Code[0x1000]; + uint32_t getFutureCycle(std::chrono::nanoseconds delay) const { return cycle + durationToCycles(delay); } + std::chrono::nanoseconds getFutureTime(uint32_t futureCycle) const { + return std::chrono::nanoseconds(int32_t(futureCycle - cycle) * 1'000'000'000 / g_emulator->m_psxClockSpeed); + } + static constexpr uint32_t durationToCycles(std::chrono::nanoseconds duration) { + return duration.count() * g_emulator->m_psxClockSpeed / 1'000'000'000; + } }; // R3000A Instruction Macros diff --git a/src/gui/gui.cc b/src/gui/gui.cc index 1b33bdbf4..b7e640723 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -957,13 +957,13 @@ void PCSX::GUI::endFrame() { ImGui::Separator(); if (ImGui::MenuItem(_("Open LID"))) { - // Open lid forever + PCSX::g_emulator->m_cdrom->openLid(); } if (ImGui::MenuItem(_("Close LID"))) { - // Close lid forever + PCSX::g_emulator->m_cdrom->closeLid(); } if (ImGui::MenuItem(_("Open and close LID"))) { - // Open lid, and schedule a close lid + PCSX::g_emulator->m_cdrom->scheduleCloseLid(); } ImGui::Separator(); if (ImGui::MenuItem(_("Reboot"))) { From f3e746a7805b205ed79257c9cde18b18a6e37167 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 20 Dec 2022 22:01:13 -0800 Subject: [PATCH 009/185] More chrono helpers. --- src/core/cdrom.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 9971fbcd6..0e00f4df0 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -107,8 +107,13 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: scheduling callback in %d cycles\n", cycles); PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDR, cycles); } + void schedule(std::chrono::nanoseconds delay) { schedule(PCSX::psxRegisters::durationToCycles(delay)); } + + void scheduleRead(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDREAD, cycles); } + void scheduleRead(std::chrono::nanoseconds delay) { scheduleRead(PCSX::psxRegisters::durationToCycles(delay)); } void scheduleDMA(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRDMA, cycles); } + void scheduleDMA(std::chrono::nanoseconds delay) { scheduleDMA(PCSX::psxRegisters::durationToCycles(delay)); } void triggerIRQ() { psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); } From 4c2ef615974c13bf05bb089b34c4778d5d8a4b34 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 20 Dec 2022 22:01:26 -0800 Subject: [PATCH 010/185] ACK 0x18 handled. --- src/core/cdrom.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 0e00f4df0..496e3b594 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -254,6 +254,11 @@ class CDRomImpl final : public PCSX::CDRom { // TODO: act on this? return; } + if (value == 0x18) { + // request ack? + // TODO: act on this? + return; + } if (value == 0x1f) { // all ack? // TODO: act on this? From 48298c8a86085303c9bab1def9cddc9d25ad43d4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 20 Dec 2022 22:01:36 -0800 Subject: [PATCH 011/185] More comments. --- src/core/cdrom.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 496e3b594..2c6cd5bef 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -314,6 +314,9 @@ class CDRomImpl final : public PCSX::CDRom { case 1: { // TODO: Verify that the command is aborted if // these parameters are indeed wrong. + // Also probably should error out if no disc or + // lid open? + // What happens when issued during Read / Play? auto maybeMSF = getMSF(m_paramFIFO); if ((m_paramFIFOSize == 3) && (maybeMSF.has_value())) { m_cause = Cause::Acknowledge; From 8627aeae0a148d44f5dc54b5b952a0cdea65db46 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 20 Dec 2022 22:01:57 -0800 Subject: [PATCH 012/185] Adding read interrupt again. --- src/core/cdrom.cc | 2 ++ src/core/cdrom.h | 5 +++-- src/core/r3000a.cc | 1 + src/core/r3000a.h | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 2c6cd5bef..d446d946d 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -101,6 +101,8 @@ class CDRomImpl final : public PCSX::CDRom { (this->*handler)(); } + void readInterrupt() override {} + void dmaInterrupt() override {} void schedule(uint32_t cycles) { diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 958b70df0..e52c61788 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -83,6 +83,7 @@ class CDRom { virtual void reset() = 0; virtual void interrupt() = 0; + virtual void readInterrupt() = 0; virtual void dmaInterrupt() = 0; virtual uint8_t read0() = 0; virtual uint8_t read1() = 0; @@ -131,8 +132,8 @@ class CDRom { }; Cause m_cause = Cause::None; - IEC60908b::MSF m_currentPosition; - IEC60908b::MSF m_seekPosition; + MSF m_currentPosition; + MSF m_seekPosition; private: friend class Widgets::IsoBrowser; diff --git a/src/core/r3000a.cc b/src/core/r3000a.cc index 90c8e4077..d2eef93a7 100644 --- a/src/core/r3000a.cc +++ b/src/core/r3000a.cc @@ -312,6 +312,7 @@ void PCSX::R3000Acpu::branchTest() { checkAndUpdate(PSXINT_SIO, g_emulator->m_sio->interrupt); checkAndUpdate(PSXINT_SIO1, g_emulator->m_sio1->interrupt); checkAndUpdate(PSXINT_CDR, g_emulator->m_cdrom->interrupt); + checkAndUpdate(PSXINT_CDREAD, g_emulator->m_cdrom->readInterrupt); checkAndUpdate(PSXINT_GPUDMA, GPU::gpuInterrupt); checkAndUpdate(PSXINT_MDECOUTDMA, g_emulator->m_mdec->mdec1Interrupt); checkAndUpdate(PSXINT_SPUDMA, spuInterrupt); diff --git a/src/core/r3000a.h b/src/core/r3000a.h index e1145b100..a23fbb14b 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -178,6 +178,7 @@ enum { PSXINT_SIO = 0, PSXINT_SIO1, PSXINT_CDR, + PSXINT_CDREAD, PSXINT_GPUDMA, PSXINT_MDECOUTDMA, PSXINT_SPUDMA, From b117fcea92dcbb13f7ea374a468c1ed863d5ce79 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 21 Dec 2022 18:01:14 -0800 Subject: [PATCH 013/185] Fixing clang build. --- src/core/cdrom.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index d446d946d..3b1bf8479 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -71,7 +71,7 @@ class CDRomImpl final : public PCSX::CDRom { static constexpr size_t c_cdCmdEnumCount = magic_enum::enum_count(); static constexpr bool isValidBCD(uint8_t value) { return (value & 0x0f) <= 9 && (value & 0xf0) <= 0x90; } - static constexpr std::optional getMSF(uint8_t *msf) { + static std::optional getMSF(uint8_t *msf) { bool validBCD = isValidBCD(msf[0]) && isValidBCD(msf[1]) && isValidBCD(msf[2]); if (!validBCD) return {}; uint8_t m = PCSX::IEC60908b::btoi(msf[0]); From 16ec00835082629cf895c5671f6711494fe4789d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 21 Dec 2022 18:06:37 -0800 Subject: [PATCH 014/185] Figured timings for command 10. --- src/core/cdrom.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 3b1bf8479..1c6862c8b 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -336,20 +336,21 @@ class CDRomImpl final : public PCSX::CDRom { // Command 10. void cdlReset() { + using namespace std::chrono_literals; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlReset, state = %i\n", m_state); switch (m_state) { case 0: // TODO: figure out exactly the various states of the CD-Rom controller - // that are being reset, and their value. Also figure out proper timings. + // that are being reset, and their value. m_state = 1; - schedule(5'000); + schedule(2ms); break; case 1: m_cause = Cause::Acknowledge; m_state = 2; triggerIRQ(); // TODO: should we wait for ack first? - schedule(5'000); + schedule(120ms); break; case 2: m_cause = Cause::Complete; From 2957f834248b92e98797f5bb828fff54bc3997da Mon Sep 17 00:00:00 2001 From: Nicolas 'Pixel' Noble Date: Wed, 21 Dec 2022 19:24:12 -0800 Subject: [PATCH 015/185] Adding basic cdrom test. --- src/mips/common.mk | 6 +++ src/mips/tests/Makefile | 11 +++-- src/mips/tests/basic/Makefile | 40 +----------------- src/mips/tests/cdrom/Makefile | 8 ++++ src/mips/tests/cdrom/cdrom.c | 76 +++++++++++++++++++++++++++++++++++ src/mips/tests/cop0/Makefile | 44 +------------------- src/mips/tests/cpu/Makefile | 44 +------------------- src/mips/tests/libc/Makefile | 40 +----------------- src/mips/tests/pcdrv/Makefile | 40 +----------------- third_party/uC-sdk | 2 +- 10 files changed, 103 insertions(+), 208 deletions(-) create mode 100644 src/mips/tests/cdrom/Makefile create mode 100644 src/mips/tests/cdrom/cdrom.c diff --git a/src/mips/common.mk b/src/mips/common.mk index 7a5c67a5f..fa144104a 100644 --- a/src/mips/common.mk +++ b/src/mips/common.mk @@ -43,9 +43,15 @@ LDFLAGS += $(ARCHFLAGS) -Wl,--oformat=$(FORMAT) CPPFLAGS_Release += -Os LDFLAGS_Release += -Os +CPPFLAGS_ReleaseFast += -O3 +LDFLAGS_ReleaseFast += -O3 + CPPFLAGS_LTO += -Os -flto LDFLAGS_LTO += -Os -flto +CPPFLAGS_LTOFast += -O3 -flto +LDFLAGS_LTOFast += -O3 -flto + CPPFLAGS_Debug += -O0 CPPFLAGS_SmallDebug += -Og CPPFLAGS_Coverage += -Og diff --git a/src/mips/tests/Makefile b/src/mips/tests/Makefile index 3a687830a..1ba908593 100644 --- a/src/mips/tests/Makefile +++ b/src/mips/tests/Makefile @@ -1,13 +1,16 @@ all: $(MAKE) -C basic all - $(MAKE) -C libc all - $(MAKE) -C cpu all + $(MAKE) -C cdrom all $(MAKE) -C cop0 all + $(MAKE) -C cpu all + $(MAKE) -C libc all $(MAKE) -C pcdrv all clean: $(MAKE) -C basic clean - $(MAKE) -C libc clean - $(MAKE) -C cpu clean + $(MAKE) -C cdrom clean $(MAKE) -C cop0 clean + $(MAKE) -C cpu clean + $(MAKE) -C libc clean $(MAKE) -C pcdrv clean + diff --git a/src/mips/tests/basic/Makefile b/src/mips/tests/basic/Makefile index 4d2f670bf..4c70dbe84 100644 --- a/src/mips/tests/basic/Makefile +++ b/src/mips/tests/basic/Makefile @@ -1,46 +1,8 @@ TARGET = basic -USE_FUNCTION_SECTIONS = false -TYPE = ps-exe -SRCS = \ -../uC-sdk-glue/BoardConsole.c \ -../uC-sdk-glue/BoardInit.c \ -../uC-sdk-glue/init.c \ -\ -../../../../third_party/uC-sdk/libc/src/cxx-glue.c \ -../../../../third_party/uC-sdk/libc/src/errno.c \ -../../../../third_party/uC-sdk/libc/src/initfini.c \ -../../../../third_party/uC-sdk/libc/src/malloc.c \ -../../../../third_party/uC-sdk/libc/src/qsort.c \ -../../../../third_party/uC-sdk/libc/src/rand.c \ -../../../../third_party/uC-sdk/libc/src/reent.c \ -../../../../third_party/uC-sdk/libc/src/stdio.c \ -../../../../third_party/uC-sdk/libc/src/string.c \ -../../../../third_party/uC-sdk/libc/src/strto.c \ -../../../../third_party/uC-sdk/libc/src/unistd.c \ -../../../../third_party/uC-sdk/libc/src/xprintf.c \ -../../../../third_party/uC-sdk/libc/src/xscanf.c \ -../../../../third_party/uC-sdk/libc/src/yscanf.c \ -../../../../third_party/uC-sdk/os/src/devfs.c \ -../../../../third_party/uC-sdk/os/src/filesystem.c \ -../../../../third_party/uC-sdk/os/src/fio.c \ -../../../../third_party/uC-sdk/os/src/hash-djb2.c \ -../../../../third_party/uC-sdk/os/src/init.c \ -../../../../third_party/uC-sdk/os/src/osdebug.c \ -../../../../third_party/uC-sdk/os/src/romfs.c \ -../../../../third_party/uC-sdk/os/src/sbrk.c \ - - -CPPFLAGS = -DNOFLOATINGPOINT -CPPFLAGS += -I. -CPPFLAGS += -I../../../../third_party/uC-sdk/libc/include -CPPFLAGS += -I../../../../third_party/uC-sdk/os/include -CPPFLAGS += -I../../../../third_party/libcester/include -CPPFLAGS += -I../../openbios/uC-sdk-glue +include ../common.mk SRCS += \ -../../common/syscalls/printf.s \ -../../common/crt0/uC-sdk-crt0.s \ basic.c \ include ../../common.mk diff --git a/src/mips/tests/cdrom/Makefile b/src/mips/tests/cdrom/Makefile new file mode 100644 index 000000000..eb20bdf34 --- /dev/null +++ b/src/mips/tests/cdrom/Makefile @@ -0,0 +1,8 @@ +TARGET = cdrom + +include ../common.mk + +SRCS += \ +cdrom.c \ + +include ../../common.mk diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c new file mode 100644 index 000000000..b353b84ad --- /dev/null +++ b/src/mips/tests/cdrom/cdrom.c @@ -0,0 +1,76 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "common/hardware/cdrom.h" +#include "common/hardware/hwregs.h" +#include "common/hardware/irq.h" + +#undef unix +#define CESTER_NO_SIGNAL +#define CESTER_NO_TIME +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 +#include "exotic/cester.h" + +#include "cester-hw.c" + +// clang-format off + +CESTER_TEST(cdlInitBasic, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 1; + CDROM_REG3 = 0x1f; + CDROM_REG0 = 1; + CDROM_REG2 = 0x1f; + CDROM_REG0 = 0; + CDROM_REG1 = CDL_INIT; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = getCDRomStat(); + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t stat2 = getCDRomStat(); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0, stat1); + cester_assert_uint_eq(0, stat2); + cester_assert_uint_ge(ackTime, 800); + cester_assert_uint_lt(ackTime, 5000); + // These may be a bit flaky on real hardware, depending on the motors status when starting. + cester_assert_uint_ge(completeTime, 50000); + cester_assert_uint_lt(completeTime, 150000); + ramsyscall_printf("CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) diff --git a/src/mips/tests/cop0/Makefile b/src/mips/tests/cop0/Makefile index 81dccab5c..8291f3558 100644 --- a/src/mips/tests/cop0/Makefile +++ b/src/mips/tests/cop0/Makefile @@ -1,50 +1,8 @@ TARGET = cop0 -USE_FUNCTION_SECTIONS = false -TYPE = ps-exe -SRCS = \ -../uC-sdk-glue/BoardConsole.c \ -../uC-sdk-glue/BoardInit.c \ -../uC-sdk-glue/init.c \ -\ -../../../../third_party/uC-sdk/libc/src/cxx-glue.c \ -../../../../third_party/uC-sdk/libc/src/errno.c \ -../../../../third_party/uC-sdk/libc/src/initfini.c \ -../../../../third_party/uC-sdk/libc/src/malloc.c \ -../../../../third_party/uC-sdk/libc/src/qsort.c \ -../../../../third_party/uC-sdk/libc/src/rand.c \ -../../../../third_party/uC-sdk/libc/src/reent.c \ -../../../../third_party/uC-sdk/libc/src/stdio.c \ -../../../../third_party/uC-sdk/libc/src/string.c \ -../../../../third_party/uC-sdk/libc/src/strto.c \ -../../../../third_party/uC-sdk/libc/src/unistd.c \ -../../../../third_party/uC-sdk/libc/src/xprintf.c \ -../../../../third_party/uC-sdk/libc/src/xscanf.c \ -../../../../third_party/uC-sdk/libc/src/yscanf.c \ -../../../../third_party/uC-sdk/os/src/devfs.c \ -../../../../third_party/uC-sdk/os/src/filesystem.c \ -../../../../third_party/uC-sdk/os/src/fio.c \ -../../../../third_party/uC-sdk/os/src/hash-djb2.c \ -../../../../third_party/uC-sdk/os/src/init.c \ -../../../../third_party/uC-sdk/os/src/osdebug.c \ -../../../../third_party/uC-sdk/os/src/romfs.c \ -../../../../third_party/uC-sdk/os/src/sbrk.c \ - - -CPPFLAGS = -DNOFLOATINGPOINT -CPPFLAGS += -I. -CPPFLAGS += -I../../../../third_party/uC-sdk/libc/include -CPPFLAGS += -I../../../../third_party/uC-sdk/os/include -CPPFLAGS += -I../../../../third_party/libcester/include -CPPFLAGS += -I../../openbios/uC-sdk-glue - -ifeq ($(PCSX_TESTS),true) -CPPFLAGS += -DPCSX_TESTS=1 -endif +include ../common.mk SRCS += \ -../../common/syscalls/printf.s \ -../../common/crt0/uC-sdk-crt0.s \ cop0.c \ exceptions.cpp \ diff --git a/src/mips/tests/cpu/Makefile b/src/mips/tests/cpu/Makefile index 84307ec73..5a3571827 100644 --- a/src/mips/tests/cpu/Makefile +++ b/src/mips/tests/cpu/Makefile @@ -1,50 +1,8 @@ TARGET = cpu -USE_FUNCTION_SECTIONS = false -TYPE = ps-exe -SRCS = \ -../uC-sdk-glue/BoardConsole.c \ -../uC-sdk-glue/BoardInit.c \ -../uC-sdk-glue/init.c \ -\ -../../../../third_party/uC-sdk/libc/src/cxx-glue.c \ -../../../../third_party/uC-sdk/libc/src/errno.c \ -../../../../third_party/uC-sdk/libc/src/initfini.c \ -../../../../third_party/uC-sdk/libc/src/malloc.c \ -../../../../third_party/uC-sdk/libc/src/qsort.c \ -../../../../third_party/uC-sdk/libc/src/rand.c \ -../../../../third_party/uC-sdk/libc/src/reent.c \ -../../../../third_party/uC-sdk/libc/src/stdio.c \ -../../../../third_party/uC-sdk/libc/src/string.c \ -../../../../third_party/uC-sdk/libc/src/strto.c \ -../../../../third_party/uC-sdk/libc/src/unistd.c \ -../../../../third_party/uC-sdk/libc/src/xprintf.c \ -../../../../third_party/uC-sdk/libc/src/xscanf.c \ -../../../../third_party/uC-sdk/libc/src/yscanf.c \ -../../../../third_party/uC-sdk/os/src/devfs.c \ -../../../../third_party/uC-sdk/os/src/filesystem.c \ -../../../../third_party/uC-sdk/os/src/fio.c \ -../../../../third_party/uC-sdk/os/src/hash-djb2.c \ -../../../../third_party/uC-sdk/os/src/init.c \ -../../../../third_party/uC-sdk/os/src/osdebug.c \ -../../../../third_party/uC-sdk/os/src/romfs.c \ -../../../../third_party/uC-sdk/os/src/sbrk.c \ - - -CPPFLAGS = -DNOFLOATINGPOINT -CPPFLAGS += -I. -CPPFLAGS += -I../../../../third_party/uC-sdk/libc/include -CPPFLAGS += -I../../../../third_party/uC-sdk/os/include -CPPFLAGS += -I../../../../third_party/libcester/include -CPPFLAGS += -I../../openbios/uC-sdk-glue - -ifeq ($(PCSX_TESTS),true) -CPPFLAGS += -DPCSX_TESTS=1 -endif +include ../common.mk SRCS += \ -../../common/syscalls/printf.s \ -../../common/crt0/uC-sdk-crt0.s \ ../cop0/exceptions.cpp \ branchbranch.s \ cpu.c \ diff --git a/src/mips/tests/libc/Makefile b/src/mips/tests/libc/Makefile index 6eb3517ec..d016e51a1 100644 --- a/src/mips/tests/libc/Makefile +++ b/src/mips/tests/libc/Makefile @@ -1,46 +1,8 @@ TARGET = libc -USE_FUNCTION_SECTIONS = false -TYPE = ps-exe -SRCS = \ -../uC-sdk-glue/BoardConsole.c \ -../uC-sdk-glue/BoardInit.c \ -../uC-sdk-glue/init.c \ -\ -../../../../third_party/uC-sdk/libc/src/cxx-glue.c \ -../../../../third_party/uC-sdk/libc/src/errno.c \ -../../../../third_party/uC-sdk/libc/src/initfini.c \ -../../../../third_party/uC-sdk/libc/src/malloc.c \ -../../../../third_party/uC-sdk/libc/src/qsort.c \ -../../../../third_party/uC-sdk/libc/src/rand.c \ -../../../../third_party/uC-sdk/libc/src/reent.c \ -../../../../third_party/uC-sdk/libc/src/stdio.c \ -../../../../third_party/uC-sdk/libc/src/string.c \ -../../../../third_party/uC-sdk/libc/src/strto.c \ -../../../../third_party/uC-sdk/libc/src/unistd.c \ -../../../../third_party/uC-sdk/libc/src/xprintf.c \ -../../../../third_party/uC-sdk/libc/src/xscanf.c \ -../../../../third_party/uC-sdk/libc/src/yscanf.c \ -../../../../third_party/uC-sdk/os/src/devfs.c \ -../../../../third_party/uC-sdk/os/src/filesystem.c \ -../../../../third_party/uC-sdk/os/src/fio.c \ -../../../../third_party/uC-sdk/os/src/hash-djb2.c \ -../../../../third_party/uC-sdk/os/src/init.c \ -../../../../third_party/uC-sdk/os/src/osdebug.c \ -../../../../third_party/uC-sdk/os/src/romfs.c \ -../../../../third_party/uC-sdk/os/src/sbrk.c \ - - -CPPFLAGS = -DNOFLOATINGPOINT -CPPFLAGS += -I. -CPPFLAGS += -I../../../../third_party/uC-sdk/libc/include -CPPFLAGS += -I../../../../third_party/uC-sdk/os/include -CPPFLAGS += -I../../../../third_party/libcester/include -CPPFLAGS += -I../../openbios/uC-sdk-glue +include ../common.mk SRCS += \ -../../common/syscalls/printf.s \ -../../common/crt0/uC-sdk-crt0.s \ libc.c \ include ../../common.mk diff --git a/src/mips/tests/pcdrv/Makefile b/src/mips/tests/pcdrv/Makefile index e5142a17c..9c5f1d042 100644 --- a/src/mips/tests/pcdrv/Makefile +++ b/src/mips/tests/pcdrv/Makefile @@ -1,46 +1,8 @@ TARGET = pcdrv -USE_FUNCTION_SECTIONS = false -TYPE = ps-exe -SRCS = \ -../uC-sdk-glue/BoardConsole.c \ -../uC-sdk-glue/BoardInit.c \ -../uC-sdk-glue/init.c \ -\ -../../../../third_party/uC-sdk/libc/src/cxx-glue.c \ -../../../../third_party/uC-sdk/libc/src/errno.c \ -../../../../third_party/uC-sdk/libc/src/initfini.c \ -../../../../third_party/uC-sdk/libc/src/malloc.c \ -../../../../third_party/uC-sdk/libc/src/qsort.c \ -../../../../third_party/uC-sdk/libc/src/rand.c \ -../../../../third_party/uC-sdk/libc/src/reent.c \ -../../../../third_party/uC-sdk/libc/src/stdio.c \ -../../../../third_party/uC-sdk/libc/src/string.c \ -../../../../third_party/uC-sdk/libc/src/strto.c \ -../../../../third_party/uC-sdk/libc/src/unistd.c \ -../../../../third_party/uC-sdk/libc/src/xprintf.c \ -../../../../third_party/uC-sdk/libc/src/xscanf.c \ -../../../../third_party/uC-sdk/libc/src/yscanf.c \ -../../../../third_party/uC-sdk/os/src/devfs.c \ -../../../../third_party/uC-sdk/os/src/filesystem.c \ -../../../../third_party/uC-sdk/os/src/fio.c \ -../../../../third_party/uC-sdk/os/src/hash-djb2.c \ -../../../../third_party/uC-sdk/os/src/init.c \ -../../../../third_party/uC-sdk/os/src/osdebug.c \ -../../../../third_party/uC-sdk/os/src/romfs.c \ -../../../../third_party/uC-sdk/os/src/sbrk.c \ - - -CPPFLAGS = -DNOFLOATINGPOINT -CPPFLAGS += -I. -CPPFLAGS += -I../../../../third_party/uC-sdk/libc/include -CPPFLAGS += -I../../../../third_party/uC-sdk/os/include -CPPFLAGS += -I../../../../third_party/libcester/include -CPPFLAGS += -I../../openbios/uC-sdk-glue +include ../common.mk SRCS += \ -../../common/syscalls/printf.s \ -../../common/crt0/uC-sdk-crt0.s \ pcdrv.c \ include ../../common.mk diff --git a/third_party/uC-sdk b/third_party/uC-sdk index 68ecb23d5..69e068718 160000 --- a/third_party/uC-sdk +++ b/third_party/uC-sdk @@ -1 +1 @@ -Subproject commit 68ecb23d5d5f86e4808bac4156ce687e430fc74d +Subproject commit 69e06871824e2d62069487a7426ded09090ceb69 From 994904173c81bb2b3def49c4ade73d4904148953 Mon Sep 17 00:00:00 2001 From: Nicolas 'Pixel' Noble Date: Wed, 21 Dec 2022 19:34:56 -0800 Subject: [PATCH 016/185] Forgot new file. --- src/mips/tests/common.mk | 43 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/mips/tests/common.mk diff --git a/src/mips/tests/common.mk b/src/mips/tests/common.mk new file mode 100644 index 000000000..24c28cda9 --- /dev/null +++ b/src/mips/tests/common.mk @@ -0,0 +1,43 @@ +USE_FUNCTION_SECTIONS = false +TYPE = ps-exe + +SRCS = \ +../uC-sdk-glue/BoardConsole.c \ +../uC-sdk-glue/BoardInit.c \ +../uC-sdk-glue/init.c \ +\ +../../../../third_party/uC-sdk/libc/src/cxx-glue.c \ +../../../../third_party/uC-sdk/libc/src/errno.c \ +../../../../third_party/uC-sdk/libc/src/initfini.c \ +../../../../third_party/uC-sdk/libc/src/malloc.c \ +../../../../third_party/uC-sdk/libc/src/qsort.c \ +../../../../third_party/uC-sdk/libc/src/rand.c \ +../../../../third_party/uC-sdk/libc/src/reent.c \ +../../../../third_party/uC-sdk/libc/src/stdio.c \ +../../../../third_party/uC-sdk/libc/src/string.c \ +../../../../third_party/uC-sdk/libc/src/strto.c \ +../../../../third_party/uC-sdk/libc/src/unistd.c \ +../../../../third_party/uC-sdk/libc/src/xprintf.c \ +../../../../third_party/uC-sdk/libc/src/xscanf.c \ +../../../../third_party/uC-sdk/libc/src/yscanf.c \ +../../../../third_party/uC-sdk/os/src/devfs.c \ +../../../../third_party/uC-sdk/os/src/filesystem.c \ +../../../../third_party/uC-sdk/os/src/fio.c \ +../../../../third_party/uC-sdk/os/src/hash-djb2.c \ +../../../../third_party/uC-sdk/os/src/init.c \ +../../../../third_party/uC-sdk/os/src/osdebug.c \ +../../../../third_party/uC-sdk/os/src/romfs.c \ +../../../../third_party/uC-sdk/os/src/sbrk.c \ +../../common/syscalls/printf.s \ +../../common/crt0/uC-sdk-crt0.s \ + +CPPFLAGS = -DNOFLOATINGPOINT +CPPFLAGS += -I. +CPPFLAGS += -I../../../../third_party/uC-sdk/libc/include +CPPFLAGS += -I../../../../third_party/uC-sdk/os/include +CPPFLAGS += -I../../../../third_party/libcester/include +CPPFLAGS += -I../../openbios/uC-sdk-glue + +ifeq ($(PCSX_TESTS),true) +CPPFLAGS += -DPCSX_TESTS=1 +endif From 0a1ef5890e4eccdf0565a4d808b8f0d1c90881fe Mon Sep 17 00:00:00 2001 From: Nicolas 'Pixel' Noble Date: Wed, 21 Dec 2022 19:40:36 -0800 Subject: [PATCH 017/185] Another forgotten file. --- src/mips/tests/cdrom/cester-hw.c | 95 ++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 src/mips/tests/cdrom/cester-hw.c diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c new file mode 100644 index 000000000..7ea0ae81a --- /dev/null +++ b/src/mips/tests/cdrom/cester-hw.c @@ -0,0 +1,95 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// This file isn't to be compiled directly. It's to be included in every +// sub test .c file that wants to do hardware measurements. + +// clang-format off + +#include "common/syscalls/syscalls.h" + +CESTER_BODY( + static int s_interruptsWereEnabled = 0; + static uint16_t s_oldMode = 0; + static uint32_t s_lastHSyncCounter = 0; + static uint32_t s_currentTime = 0; + static const unsigned US_PER_HBLANK = 64; + + static inline void initializeTime() { + s_lastHSyncCounter = COUNTERS[1].value; + s_currentTime = 0; + } + + static inline uint32_t updateTime() { + uint32_t lastHSyncCounter = s_lastHSyncCounter; + uint32_t hsyncCounter = COUNTERS[1].value; + if (hsyncCounter < lastHSyncCounter) { + hsyncCounter += 0x10000; + } + uint32_t currentTime = s_currentTime = s_currentTime + (hsyncCounter - lastHSyncCounter) * US_PER_HBLANK; + s_lastHSyncCounter = hsyncCounter; + return currentTime; + } + + static inline uint32_t waitCDRomIRQ() { + uint32_t time; + do { + time = updateTime(); + } while ((IREG & IRQ_CDROM) == 0); + IREG &= ~IRQ_CDROM; + return time; + } + + static inline uint8_t ackCDRomCause() { + CDROM_REG0 = 1; + uint8_t cause = CDROM_REG3_UC; + if (cause & 7) { + CDROM_REG0 = 1; + CDROM_REG3 = 7; + } + if (cause & 0x18) { + CDROM_REG0 = 1; + CDROM_REG3 = cause & 0x18; + } + return cause & 7; + } + + static inline uint8_t getCDRomStat() { + CDROM_REG0 = 0; + return CDROM_REG1_UC & ~3; + } +) + +CESTER_BEFORE_ALL(cpu_tests, + s_interruptsWereEnabled = enterCriticalSection(); + s_oldMode = COUNTERS[1].mode; + COUNTERS[1].mode = 0x0100; +) + +CESTER_AFTER_ALL(cpu_tests, + COUNTERS[1].mode = s_oldMode; + if (s_interruptsWereEnabled) leaveCriticalSection(); +) From caaf0ccef4a6051c777b32fa3c60a6b20e1b861e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 21 Dec 2022 20:47:03 -0800 Subject: [PATCH 018/185] Adding delayed init test. --- src/mips/tests/cdrom/cdrom.c | 59 +++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index b353b84ad..5a228b40c 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -65,12 +65,69 @@ CESTER_TEST(cdlInitBasic, test_instance, cester_assert_uint_eq(2, cause2); cester_assert_uint_eq(0, stat1); cester_assert_uint_eq(0, stat2); + // Typical value seems to be around 2ms. cester_assert_uint_ge(ackTime, 800); cester_assert_uint_lt(ackTime, 5000); // These may be a bit flaky on real hardware, depending on the motors status when starting. + // Typical value seems to be around 120ms. cester_assert_uint_ge(completeTime, 50000); cester_assert_uint_lt(completeTime, 150000); - ramsyscall_printf("CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); + ramsyscall_printf("Basic initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) + +CESTER_TEST(cdlInitDelayed, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 1; + CDROM_REG3 = 0x1f; + CDROM_REG0 = 1; + CDROM_REG2 = 0x1f; + CDROM_REG0 = 0; + CDROM_REG1 = CDL_INIT; + + uint32_t ackTime = waitCDRomIRQ(); + + // We shouldn't get another IRQ until we acknowledge the previous one + // directly to the controller. But the initialization will continue + // in the background nonetheless. Wait 500ms, since the controller + // finishes its initialization in roughly 120ms. + uint32_t delayedTime; + do { + delayedTime = updateTime(); + } while (((IREG & IRQ_CDROM) == 0) && (delayedTime <= 500000)); + int gotIRQ = (IREG & IRQ_CDROM) != 0; + if (gotIRQ) IREG &= ~IRQ_CDROM; + + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = getCDRomStat(); + + initializeTime(); + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t stat2 = getCDRomStat(); + + cester_assert_false(gotIRQ); + cester_assert_uint_ge(delayedTime, 500000); + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0, stat1); + cester_assert_uint_eq(0, stat2); + // This still takes about 2ms. + cester_assert_uint_ge(ackTime, 800); + cester_assert_uint_lt(ackTime, 5000); + // Since the initialization completes in the background of the controller + // waiting its ack, we're really only measuring the roundtrip of the + // communication between the CPU and the mechacon. It typically takes 750us + // to do this roundtrip. + cester_assert_uint_lt(completeTime, 2000); + ramsyscall_printf("Delayed initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); IMASK = imask; ) From 732ae8604aaacf576a3bd38ae6fdb7df473ed82b Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 21 Dec 2022 22:12:43 -0800 Subject: [PATCH 019/185] Enhancing test. --- src/mips/tests/cdrom/cdrom.c | 30 ++++++++++++++++++++++-------- src/mips/tests/cdrom/cester-hw.c | 13 ++++++++----- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 5a228b40c..30152e93c 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -55,16 +55,28 @@ CESTER_TEST(cdlInitBasic, test_instance, uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = getCDRomStat(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t stat2 = CDROM_REG0 & ~3; uint32_t completeTime = waitCDRomIRQ() - ackTime; uint8_t cause2 = ackCDRomCause(); - uint8_t stat2 = getCDRomStat(); + uint8_t stat3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t stat4 = CDROM_REG0 & ~3; cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(2, cause2); - cester_assert_uint_eq(0, stat1); - cester_assert_uint_eq(0, stat2); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, stat3); + cester_assert_uint_eq(0x18, stat4); // Typical value seems to be around 2ms. cester_assert_uint_ge(ackTime, 800); cester_assert_uint_lt(ackTime, 5000); @@ -105,20 +117,22 @@ CESTER_TEST(cdlInitDelayed, test_instance, if (gotIRQ) IREG &= ~IRQ_CDROM; uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = getCDRomStat(); + CDROM_REG1; + uint8_t stat1 = CDROM_REG0 & ~3; initializeTime(); uint32_t completeTime = waitCDRomIRQ(); uint8_t cause2 = ackCDRomCause(); - uint8_t stat2 = getCDRomStat(); + CDROM_REG1; + uint8_t stat2 = CDROM_REG0 & ~3; cester_assert_false(gotIRQ); cester_assert_uint_ge(delayedTime, 500000); cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(2, cause2); - cester_assert_uint_eq(0, stat1); - cester_assert_uint_eq(0, stat2); + cester_assert_uint_eq(0x18, stat1); + cester_assert_uint_eq(0x18, stat2); // This still takes about 2ms. cester_assert_uint_ge(ackTime, 800); cester_assert_uint_lt(ackTime, 5000); diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index 7ea0ae81a..ff50fecba 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -38,6 +38,14 @@ CESTER_BODY( static uint32_t s_currentTime = 0; static const unsigned US_PER_HBLANK = 64; + static uint8_t readResponse(uint8_t response[16]) { + uint8_t responseSize = 0; + while ((CDROM_REG0 & 0x20) && (responseSize < 16)) { + response[responseSize++] = CDROM_REG1; + } + return responseSize; + } + static inline void initializeTime() { s_lastHSyncCounter = COUNTERS[1].value; s_currentTime = 0; @@ -76,11 +84,6 @@ CESTER_BODY( } return cause & 7; } - - static inline uint8_t getCDRomStat() { - CDROM_REG0 = 0; - return CDROM_REG1_UC & ~3; - } ) CESTER_BEFORE_ALL(cpu_tests, From b15fced8457314a0518e61085016b7cf86b7647a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 21 Dec 2022 22:28:59 -0800 Subject: [PATCH 020/185] Further enhancing test. --- src/mips/tests/cdrom/cdrom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 30152e93c..4249b0445 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -59,6 +59,8 @@ CESTER_TEST(cdlInitBasic, test_instance, uint8_t response1[16]; uint8_t responseSize1 = readResponse(response1); uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; uint32_t completeTime = waitCDRomIRQ() - ackTime; uint8_t cause2 = ackCDRomCause(); @@ -66,9 +68,13 @@ CESTER_TEST(cdlInitBasic, test_instance, uint8_t response2[16]; uint8_t responseSize2 = readResponse(response2); uint8_t stat4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); cester_assert_uint_eq(2, response1[0]); cester_assert_uint_eq(1, responseSize1); cester_assert_uint_eq(2, response2[0]); From 574b2cd9fc46e4fea4a01738fe29ab974d30f560 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 21 Dec 2022 23:36:23 -0800 Subject: [PATCH 021/185] Making the enhanced test pass. --- src/core/cdrom.cc | 50 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 1c6862c8b..9761a82be 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -93,6 +93,11 @@ class CDRomImpl final : public PCSX::CDRom { m_busy = false; m_state = 0; m_command = 0; + m_cause = Cause::None; + m_currentPosition.reset(); + m_seekPosition.reset(); + m_gotAck = false; + m_waitingAck = false; } void interrupt() override { @@ -117,7 +122,11 @@ class CDRomImpl final : public PCSX::CDRom { void scheduleDMA(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRDMA, cycles); } void scheduleDMA(std::chrono::nanoseconds delay) { scheduleDMA(PCSX::psxRegisters::durationToCycles(delay)); } - void triggerIRQ() { psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); } + void triggerIRQ() { + assert(!m_waitingAck); + m_gotAck = false; + psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + } void clearIRQ() { psxHu32ref(0x1070) &= SWAP_LE32(~uint32_t(4)); } @@ -169,7 +178,10 @@ class CDRomImpl final : public PCSX::CDRom { case 1: { // cause // TODO: add bit 4 - return magic_enum::enum_integer(m_cause) | 0xe0; + uint8_t ret = magic_enum::enum_integer(m_cause) | 0xe0; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: read cause, returning %02x\n", ret); + m_cause = Cause::None; + return ret; } break; } // should not be reachable @@ -250,11 +262,11 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->pause(); } break; case 1: { + bool ack = false; // cause ack if (value == 0x07) { // partial ack? - // TODO: act on this? - return; + ack = true; } if (value == 0x18) { // request ack? @@ -263,7 +275,17 @@ class CDRomImpl final : public PCSX::CDRom { } if (value == 0x1f) { // all ack? - // TODO: act on this? + ack = true; + } + if (ack) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: got ack\n"); + if (m_waitingAck) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: was waiting on ack\n"); + using namespace std::chrono_literals; + m_waitingAck = false; + schedule(750us); + } + m_gotAck = true; return; } PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:1 not available yet\n"); @@ -288,7 +310,6 @@ class CDRomImpl final : public PCSX::CDRom { } void startCommand(uint8_t command) { - m_busy = true; m_command = command; if (PCSX::g_emulator->settings.get() .get()) { @@ -343,19 +364,32 @@ class CDRomImpl final : public PCSX::CDRom { // TODO: figure out exactly the various states of the CD-Rom controller // that are being reset, and their value. m_state = 1; + m_currentPosition.reset(); + m_seekPosition.reset(); schedule(2ms); break; case 1: m_cause = Cause::Acknowledge; m_state = 2; + m_responseFIFOSize = 1; + m_responseFIFOIndex = 0; + m_responseFIFO[0] = 2; triggerIRQ(); - // TODO: should we wait for ack first? schedule(120ms); break; case 2: + if (!m_gotAck) { + m_waitingAck = true; + m_state = 3; + break; + } + [[fallthrough]]; + case 3: m_cause = Cause::Complete; m_state = 0; - m_busy = false; + m_responseFIFOSize = 1; + m_responseFIFOIndex = 0; + m_responseFIFO[0] = 2; m_command = 0; triggerIRQ(); break; From 7acd39b737e4127b397d699b07ee7458c336b65e Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 21 Dec 2022 23:53:44 -0800 Subject: [PATCH 022/185] Forgot to commit this file... --- src/core/cdrom.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.h b/src/core/cdrom.h index e52c61788..30c3949c8 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -102,7 +102,7 @@ class CDRom { bool dataFIFOEmpty() { return m_dataFIFOIndex == m_dataFIFOSize; } bool paramFIFOAvailable() { return m_paramFIFOSize != 16; } - bool responseFIFOHasData() { return m_responseFIFOIndex == m_responseFIFOSize; } + bool responseFIFOHasData() { return m_responseFIFOIndex != m_responseFIFOSize; } bool m_lidOpened = false; bool m_lidCloseScheduled = false; @@ -119,6 +119,8 @@ class CDRom { uint8_t m_responseFIFOSize = 0; uint8_t m_registerIndex = 0; bool m_busy = false; + bool m_gotAck = false; + bool m_waitingAck = false; uint8_t m_state = 0; uint8_t m_command = 0; From 7d984c20c122f51d62467a4f92b2ff05587657e8 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 10:51:37 -0800 Subject: [PATCH 023/185] Swapping Init <--> Reset. --- src/core/cdrom.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 9761a82be..d066dcb93 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -46,7 +46,7 @@ class CDRomImpl final : public PCSX::CDRom { CdlStandby = 7, CdlStop = 8, CdlPause = 9, - CdlReset = 10, + CdlInit = 10, CdlMute = 11, CdlDemute = 12, CdlSetFilter = 13, @@ -64,7 +64,7 @@ class CDRomImpl final : public PCSX::CDRom { CdlTest = 25, CdlID = 26, CdlReadS = 27, - CdlInit = 28, + CdlReset = 28, CdlGetQ = 29, CdlReadToc = 30, }; @@ -356,9 +356,9 @@ class CDRomImpl final : public PCSX::CDRom { } // Command 10. - void cdlReset() { + void cdlInit() { using namespace std::chrono_literals; - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlReset, state = %i\n", m_state); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlInit, state = %i\n", m_state); switch (m_state) { case 0: // TODO: figure out exactly the various states of the CD-Rom controller @@ -407,16 +407,16 @@ class CDRomImpl final : public PCSX::CDRom { #if 0 &CDRomImpl::cdlSync, &CDRomImpl::cdlGetStat, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlPlay, // 0 &CDRomImpl::cdlForward, &CDRomImpl::cdlBackward, &CDRomImpl::cdlReadN, &CDRomImpl::cdlStandby, // 4 - &CDRomImpl::cdlStop, &CDRomImpl::cdlPause, &CDRomImpl::cdlReset, &CDRomImpl::cdlMute, // 8 + &CDRomImpl::cdlStop, &CDRomImpl::cdlPause, &CDRomImpl::cdlInit, &CDRomImpl::cdlMute, // 8 &CDRomImpl::cdlDemute, &CDRomImpl::cdlSetFilter, &CDRomImpl::cdlSetMode, &CDRomImpl::cdlGetParam, // 12 &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, &CDRomImpl::cdlReadT, &CDRomImpl::cdlGetTN, // 16 &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, &CDRomImpl::cdlSetClock, // 20 &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 - &CDRomImpl::cdlInit, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 + &CDRomImpl::cdlReset, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 #else &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlReset, &CDRomImpl::cdlUnk, // 8 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 16 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 From bfce6d18299a7625b51c9e89963e2f4305ed909e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 11:07:55 -0800 Subject: [PATCH 024/185] Slight fix on ack writes. --- src/core/cdrom.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index d066dcb93..418a6247b 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -268,11 +268,6 @@ class CDRomImpl final : public PCSX::CDRom { // partial ack? ack = true; } - if (value == 0x18) { - // request ack? - // TODO: act on this? - return; - } if (value == 0x1f) { // all ack? ack = true; @@ -288,6 +283,16 @@ class CDRomImpl final : public PCSX::CDRom { m_gotAck = true; return; } + if (value & 0x10) { + // request ack? + // TODO: act on this? + return; + } + if (value & 0x08) { + // ?? + // TODO: act on this? + return; + } PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:1 not available yet\n"); PCSX::g_system->pause(); } break; From f303bd6bddfacbad37404b95239b7340e083fbdd Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 14:06:43 -0800 Subject: [PATCH 025/185] Adding basic setloc test. --- src/mips/tests/cdrom/cdrom.c | 34 ++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cester-hw.c | 30 ++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 4249b0445..729a8db55 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -146,8 +146,42 @@ CESTER_TEST(cdlInitDelayed, test_instance, // waiting its ack, we're really only measuring the roundtrip of the // communication between the CPU and the mechacon. It typically takes 750us // to do this roundtrip. + cester_assert_uint_ge(completeTime, 150); cester_assert_uint_lt(completeTime, 2000); ramsyscall_printf("Delayed initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); IMASK = imask; ) + +CESTER_TEST(cdlSetLoc, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 2; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(2, response[0]); + cester_assert_uint_eq(1, responseSize); + // we seem to consistently get ~1000us with a pretty tight margin + // of error from this test, but let's still give it some slack. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 1500); + ramsyscall_printf("Basic setloc to 00:02:00, complete in %ius\n", completeTime); +) diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index ff50fecba..bddb92181 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -29,6 +29,8 @@ SOFTWARE. // clang-format off +#include + #include "common/syscalls/syscalls.h" CESTER_BODY( @@ -84,6 +86,34 @@ CESTER_BODY( } return cause & 7; } + + static inline int resetCDRom() { + uint32_t imask = IMASK; + uint8_t cause; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 1; + CDROM_REG3 = 0x1f; + CDROM_REG0 = 1; + CDROM_REG2 = 0x1f; + CDROM_REG0 = 0; + CDROM_REG1 = CDL_INIT; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) return 0; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 2) return 0; + + initializeTime(); + // wait 10ms for things to settle + while (updateTime() < 10000); + IMASK = imask; + return 1; + } ) CESTER_BEFORE_ALL(cpu_tests, From e1e7197d0764cfc7e232a8aef5423ab1bbe11606 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 18:58:25 -0800 Subject: [PATCH 026/185] Making test pass. --- src/core/cdrom.cc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 418a6247b..c3677b088 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -34,6 +34,8 @@ namespace { +using namespace std::chrono_literals; + class CDRomImpl final : public PCSX::CDRom { enum Commands { CdlSync = 0, @@ -335,9 +337,8 @@ class CDRomImpl final : public PCSX::CDRom { void cdlSetLoc() { switch (m_state) { case 0: - // TODO: Figure out proper timings. m_state = 1; - schedule(5'000); + schedule(1ms); break; case 1: { // TODO: Verify that the command is aborted if @@ -352,9 +353,12 @@ class CDRomImpl final : public PCSX::CDRom { } else { m_cause = Cause::Error; } + m_paramFIFOSize = 0; m_state = 0; - m_busy = false; m_command = 0; + m_responseFIFOSize = 1; + m_responseFIFOIndex = 0; + m_responseFIFO[0] = 2; triggerIRQ(); } break; } @@ -362,7 +366,6 @@ class CDRomImpl final : public PCSX::CDRom { // Command 10. void cdlInit() { - using namespace std::chrono_literals; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlInit, state = %i\n", m_state); switch (m_state) { case 0: From 065085f41e8385d363b65e6fd0e3786a1ea214c9 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 19:32:37 -0800 Subject: [PATCH 027/185] Adding error test, and some tweaks. --- src/mips/tests/cdrom/cdrom.c | 50 +++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 729a8db55..37daee818 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -126,6 +126,7 @@ CESTER_TEST(cdlInitDelayed, test_instance, CDROM_REG1; uint8_t stat1 = CDROM_REG0 & ~3; + initializeTime(); uint32_t completeTime = waitCDRomIRQ(); @@ -133,6 +134,7 @@ CESTER_TEST(cdlInitDelayed, test_instance, CDROM_REG1; uint8_t stat2 = CDROM_REG0 & ~3; + cester_assert_false(gotIRQ); cester_assert_uint_ge(delayedTime, 500000); cester_assert_uint_eq(3, cause1); @@ -144,15 +146,57 @@ CESTER_TEST(cdlInitDelayed, test_instance, cester_assert_uint_lt(ackTime, 5000); // Since the initialization completes in the background of the controller // waiting its ack, we're really only measuring the roundtrip of the - // communication between the CPU and the mechacon. It typically takes 750us + // communication between the CPU and the mechacon. It typically takes 350us // to do this roundtrip. cester_assert_uint_ge(completeTime, 150); - cester_assert_uint_lt(completeTime, 2000); + cester_assert_uint_lt(completeTime, 1000); ramsyscall_printf("Delayed initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); IMASK = imask; ) +CESTER_TEST(cdlInitWithArgs, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 1; + CDROM_REG3 = 0x1f; + CDROM_REG0 = 1; + CDROM_REG2 = 0x1f; + CDROM_REG0 = 0; + CDROM_REG2 = 0xff; + CDROM_REG2 = 0xff; + CDROM_REG2 = 0xff; + CDROM_REG2 = 0xff; + CDROM_REG1 = CDL_INIT; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(32, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + // Typical value seems to be around 1ms. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Initialization with args: CD-Rom controller errored, error in %ius\n", errorTime); + + IMASK = imask; +) + CESTER_TEST(cdlSetLoc, test_instances, int resetDone = resetCDRom(); cester_assert_true(resetDone); @@ -179,7 +223,7 @@ CESTER_TEST(cdlSetLoc, test_instances, cester_assert_uint_eq(0x18, stat2); cester_assert_uint_eq(2, response[0]); cester_assert_uint_eq(1, responseSize); - // we seem to consistently get ~1000us with a pretty tight margin + // we seem to consistently get ~1ms with a pretty tight margin // of error from this test, but let's still give it some slack. cester_assert_uint_ge(completeTime, 500); cester_assert_uint_lt(completeTime, 1500); From 0b160ea7fd3fd1ef1e27d3337a2ad5a7316f8d8b Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 19:53:00 -0800 Subject: [PATCH 028/185] One more test. --- .vscode/c_cpp_properties.json | 3 ++- src/mips/tests/cdrom/cdrom.c | 40 ++++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 2e433cdc6..8ed9339e1 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -9,7 +9,8 @@ "compilerPath": "/usr/bin/clang-9", "cStandard": "c11", "cppStandard": "c++17", - "intelliSenseMode": "clang-x64" + "intelliSenseMode": "clang-x64", + "configurationProvider": "ms-vscode.makefile-tools" } ], "version": 4 diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 37daee818..e1c07cf3c 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -39,7 +39,7 @@ SOFTWARE. // clang-format off -CESTER_TEST(cdlInitBasic, test_instance, +CESTER_TEST(cdlInit, test_instance, initializeTime(); uint32_t imask = IMASK; @@ -191,7 +191,7 @@ CESTER_TEST(cdlInitWithArgs, test_instance, cester_assert_uint_eq(0x18, stat2); // Typical value seems to be around 1ms. cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 2000); ramsyscall_printf("Initialization with args: CD-Rom controller errored, error in %ius\n", errorTime); IMASK = imask; @@ -223,9 +223,39 @@ CESTER_TEST(cdlSetLoc, test_instances, cester_assert_uint_eq(0x18, stat2); cester_assert_uint_eq(2, response[0]); cester_assert_uint_eq(1, responseSize); - // we seem to consistently get ~1ms with a pretty tight margin - // of error from this test, but let's still give it some slack. + // Typical value seems to be around 1ms. cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 1500); + cester_assert_uint_lt(completeTime, 2000); ramsyscall_printf("Basic setloc to 00:02:00, complete in %ius\n", completeTime); ) + +CESTER_TEST(cdlSetLocNoArgs, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(32, response[1]); + cester_assert_uint_eq(2, responseSize); + // we seem to consistently get ~1ms with a pretty tight margin + // of error from this test, but let's still give it some slack. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Invalid setloc with no args, errored in %ius\n", errorTime); +) From 48a4bf2e206c34322b7e60736db05ce91a649061 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 19:59:04 -0800 Subject: [PATCH 029/185] Making test pass. --- src/core/cdrom.cc | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index c3677b088..5bcb40da6 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -280,7 +280,7 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: was waiting on ack\n"); using namespace std::chrono_literals; m_waitingAck = false; - schedule(750us); + schedule(350us); } m_gotAck = true; return; @@ -350,15 +350,19 @@ class CDRomImpl final : public PCSX::CDRom { if ((m_paramFIFOSize == 3) && (maybeMSF.has_value())) { m_cause = Cause::Acknowledge; m_seekPosition = maybeMSF.value(); + m_responseFIFOSize = 1; + m_responseFIFOIndex = 0; + m_responseFIFO[0] = 2; } else { + m_responseFIFOSize = 2; + m_responseFIFOIndex = 0; + m_responseFIFO[0] = 3; + m_responseFIFO[1] = 32; m_cause = Cause::Error; } m_paramFIFOSize = 0; m_state = 0; m_command = 0; - m_responseFIFOSize = 1; - m_responseFIFOIndex = 0; - m_responseFIFO[0] = 2; triggerIRQ(); } break; } @@ -369,6 +373,11 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlInit, state = %i\n", m_state); switch (m_state) { case 0: + if (m_paramFIFOSize != 0) { + m_state = 4; + schedule(1ms); + break; + } // TODO: figure out exactly the various states of the CD-Rom controller // that are being reset, and their value. m_state = 1; @@ -401,6 +410,16 @@ class CDRomImpl final : public PCSX::CDRom { m_command = 0; triggerIRQ(); break; + case 4: + m_cause = Cause::Error; + m_state = 0; + m_paramFIFOSize = 0; + m_responseFIFOSize = 2; + m_responseFIFOIndex = 0; + m_responseFIFO[0] = 3; + m_responseFIFO[1] = 32; + m_command = 0; + triggerIRQ(); } } From d3824b1db8e1d4254376daa33bad95ce838c4d96 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 20:03:25 -0800 Subject: [PATCH 030/185] Adjusting timings a bit. --- src/mips/tests/cdrom/cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index e1c07cf3c..539114e71 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -148,7 +148,7 @@ CESTER_TEST(cdlInitDelayed, test_instance, // waiting its ack, we're really only measuring the roundtrip of the // communication between the CPU and the mechacon. It typically takes 350us // to do this roundtrip. - cester_assert_uint_ge(completeTime, 150); + cester_assert_uint_ge(completeTime, 100); cester_assert_uint_lt(completeTime, 1000); ramsyscall_printf("Delayed initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); From 22b23cadabe05796c21a9941a46430d7ea6533ce Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 20:11:50 -0800 Subject: [PATCH 031/185] Splitting this up. --- src/mips/tests/cdrom/cdlinit.c | 186 +++++++++++++++++++++++++ src/mips/tests/cdrom/cdlsetloc.c | 89 ++++++++++++ src/mips/tests/cdrom/cdrom.c | 225 +------------------------------ 3 files changed, 277 insertions(+), 223 deletions(-) create mode 100644 src/mips/tests/cdrom/cdlinit.c create mode 100644 src/mips/tests/cdrom/cdlsetloc.c diff --git a/src/mips/tests/cdrom/cdlinit.c b/src/mips/tests/cdrom/cdlinit.c new file mode 100644 index 000000000..41372b5f9 --- /dev/null +++ b/src/mips/tests/cdrom/cdlinit.c @@ -0,0 +1,186 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlInit, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 1; + CDROM_REG3 = 0x1f; + CDROM_REG0 = 1; + CDROM_REG2 = 0x1f; + CDROM_REG0 = 0; + CDROM_REG1 = CDL_INIT; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t stat3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t stat4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, stat3); + cester_assert_uint_eq(0x18, stat4); + // Typical value seems to be around 2ms. + cester_assert_uint_ge(ackTime, 800); + cester_assert_uint_lt(ackTime, 5000); + // These may be a bit flaky on real hardware, depending on the motors status when starting. + // Typical value seems to be around 120ms. + cester_assert_uint_ge(completeTime, 50000); + cester_assert_uint_lt(completeTime, 150000); + ramsyscall_printf("Basic initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) + +CESTER_TEST(cdlInitDelayed, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 1; + CDROM_REG3 = 0x1f; + CDROM_REG0 = 1; + CDROM_REG2 = 0x1f; + CDROM_REG0 = 0; + CDROM_REG1 = CDL_INIT; + + uint32_t ackTime = waitCDRomIRQ(); + + // We shouldn't get another IRQ until we acknowledge the previous one + // directly to the controller. But the initialization will continue + // in the background nonetheless. Wait 500ms, since the controller + // finishes its initialization in roughly 120ms. + uint32_t delayedTime; + do { + delayedTime = updateTime(); + } while (((IREG & IRQ_CDROM) == 0) && (delayedTime <= 500000)); + int gotIRQ = (IREG & IRQ_CDROM) != 0; + if (gotIRQ) IREG &= ~IRQ_CDROM; + + uint8_t cause1 = ackCDRomCause(); + CDROM_REG1; + uint8_t stat1 = CDROM_REG0 & ~3; + + + initializeTime(); + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + CDROM_REG1; + uint8_t stat2 = CDROM_REG0 & ~3; + + + cester_assert_false(gotIRQ); + cester_assert_uint_ge(delayedTime, 500000); + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0x18, stat1); + cester_assert_uint_eq(0x18, stat2); + // This still takes about 2ms. + cester_assert_uint_ge(ackTime, 800); + cester_assert_uint_lt(ackTime, 5000); + // Since the initialization completes in the background of the controller + // waiting its ack, we're really only measuring the roundtrip of the + // communication between the CPU and the mechacon. It typically takes 350us + // to do this roundtrip. + cester_assert_uint_ge(completeTime, 100); + cester_assert_uint_lt(completeTime, 1000); + ramsyscall_printf("Delayed initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) + +CESTER_TEST(cdlInitWithArgs, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 1; + CDROM_REG3 = 0x1f; + CDROM_REG0 = 1; + CDROM_REG2 = 0x1f; + CDROM_REG0 = 0; + CDROM_REG2 = 0xff; + CDROM_REG2 = 0xff; + CDROM_REG2 = 0xff; + CDROM_REG2 = 0xff; + CDROM_REG1 = CDL_INIT; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(32, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + // Typical value seems to be around 1ms. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 2000); + ramsyscall_printf("Initialization with args: CD-Rom controller errored, error in %ius\n", errorTime); + + IMASK = imask; +) + diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c new file mode 100644 index 000000000..947cf4f33 --- /dev/null +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -0,0 +1,89 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlSetLoc, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 2; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(2, response[0]); + cester_assert_uint_eq(1, responseSize); + // Typical value seems to be around 1ms. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 2000); + ramsyscall_printf("Basic setloc to 00:02:00, complete in %ius\n", completeTime); +) + +CESTER_TEST(cdlSetLocNoArgs, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(32, response[1]); + cester_assert_uint_eq(2, responseSize); + // Typical value seems to be around 1ms. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Invalid setloc with no args, errored in %ius\n", errorTime); +) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 539114e71..b5e1340f1 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -36,226 +36,5 @@ SOFTWARE. #include "exotic/cester.h" #include "cester-hw.c" - -// clang-format off - -CESTER_TEST(cdlInit, test_instance, - initializeTime(); - - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - - CDROM_REG0 = 1; - CDROM_REG3 = 0x1f; - CDROM_REG0 = 1; - CDROM_REG2 = 0x1f; - CDROM_REG0 = 0; - CDROM_REG1 = CDL_INIT; - - uint32_t ackTime = waitCDRomIRQ(); - uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; - uint8_t response1[16]; - uint8_t responseSize1 = readResponse(response1); - uint8_t stat2 = CDROM_REG0 & ~3; - CDROM_REG0 = 1; - uint8_t cause1b = CDROM_REG3_UC; - - uint32_t completeTime = waitCDRomIRQ() - ackTime; - uint8_t cause2 = ackCDRomCause(); - uint8_t stat3 = CDROM_REG0 & ~3; - uint8_t response2[16]; - uint8_t responseSize2 = readResponse(response2); - uint8_t stat4 = CDROM_REG0 & ~3; - CDROM_REG0 = 1; - uint8_t cause2b = CDROM_REG3_UC; - - cester_assert_uint_eq(3, cause1); - cester_assert_uint_eq(2, cause2); - cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0xe0, cause2b); - cester_assert_uint_eq(2, response1[0]); - cester_assert_uint_eq(1, responseSize1); - cester_assert_uint_eq(2, response2[0]); - cester_assert_uint_eq(1, responseSize2); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); - cester_assert_uint_eq(0x38, stat3); - cester_assert_uint_eq(0x18, stat4); - // Typical value seems to be around 2ms. - cester_assert_uint_ge(ackTime, 800); - cester_assert_uint_lt(ackTime, 5000); - // These may be a bit flaky on real hardware, depending on the motors status when starting. - // Typical value seems to be around 120ms. - cester_assert_uint_ge(completeTime, 50000); - cester_assert_uint_lt(completeTime, 150000); - ramsyscall_printf("Basic initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; -) - -CESTER_TEST(cdlInitDelayed, test_instance, - initializeTime(); - - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - - CDROM_REG0 = 1; - CDROM_REG3 = 0x1f; - CDROM_REG0 = 1; - CDROM_REG2 = 0x1f; - CDROM_REG0 = 0; - CDROM_REG1 = CDL_INIT; - - uint32_t ackTime = waitCDRomIRQ(); - - // We shouldn't get another IRQ until we acknowledge the previous one - // directly to the controller. But the initialization will continue - // in the background nonetheless. Wait 500ms, since the controller - // finishes its initialization in roughly 120ms. - uint32_t delayedTime; - do { - delayedTime = updateTime(); - } while (((IREG & IRQ_CDROM) == 0) && (delayedTime <= 500000)); - int gotIRQ = (IREG & IRQ_CDROM) != 0; - if (gotIRQ) IREG &= ~IRQ_CDROM; - - uint8_t cause1 = ackCDRomCause(); - CDROM_REG1; - uint8_t stat1 = CDROM_REG0 & ~3; - - - initializeTime(); - - uint32_t completeTime = waitCDRomIRQ(); - uint8_t cause2 = ackCDRomCause(); - CDROM_REG1; - uint8_t stat2 = CDROM_REG0 & ~3; - - - cester_assert_false(gotIRQ); - cester_assert_uint_ge(delayedTime, 500000); - cester_assert_uint_eq(3, cause1); - cester_assert_uint_eq(2, cause2); - cester_assert_uint_eq(0x18, stat1); - cester_assert_uint_eq(0x18, stat2); - // This still takes about 2ms. - cester_assert_uint_ge(ackTime, 800); - cester_assert_uint_lt(ackTime, 5000); - // Since the initialization completes in the background of the controller - // waiting its ack, we're really only measuring the roundtrip of the - // communication between the CPU and the mechacon. It typically takes 350us - // to do this roundtrip. - cester_assert_uint_ge(completeTime, 100); - cester_assert_uint_lt(completeTime, 1000); - ramsyscall_printf("Delayed initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; -) - -CESTER_TEST(cdlInitWithArgs, test_instance, - initializeTime(); - - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - - CDROM_REG0 = 1; - CDROM_REG3 = 0x1f; - CDROM_REG0 = 1; - CDROM_REG2 = 0x1f; - CDROM_REG0 = 0; - CDROM_REG2 = 0xff; - CDROM_REG2 = 0xff; - CDROM_REG2 = 0xff; - CDROM_REG2 = 0xff; - CDROM_REG1 = CDL_INIT; - - uint32_t errorTime = waitCDRomIRQ(); - uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; - uint8_t response1[16]; - uint8_t responseSize1 = readResponse(response1); - uint8_t stat2 = CDROM_REG0 & ~3; - CDROM_REG0 = 1; - uint8_t cause1b = CDROM_REG3_UC; - - cester_assert_uint_eq(5, cause1); - cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(3, response1[0]); - cester_assert_uint_eq(32, response1[1]); - cester_assert_uint_eq(2, responseSize1); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); - // Typical value seems to be around 1ms. - cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 2000); - ramsyscall_printf("Initialization with args: CD-Rom controller errored, error in %ius\n", errorTime); - - IMASK = imask; -) - -CESTER_TEST(cdlSetLoc, test_instances, - int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; - - initializeTime(); - CDROM_REG0 = 0; - CDROM_REG2 = 0; - CDROM_REG2 = 2; - CDROM_REG2 = 0; - CDROM_REG1 = CDL_SETLOC; - uint32_t completeTime = waitCDRomIRQ(); - uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; - uint8_t response[16]; - uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; - CDROM_REG0 = 1; - uint8_t cause1b = CDROM_REG3_UC; - - cester_assert_uint_eq(3, cause1); - cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); - cester_assert_uint_eq(2, response[0]); - cester_assert_uint_eq(1, responseSize); - // Typical value seems to be around 1ms. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 2000); - ramsyscall_printf("Basic setloc to 00:02:00, complete in %ius\n", completeTime); -) - -CESTER_TEST(cdlSetLocNoArgs, test_instances, - int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; - - initializeTime(); - CDROM_REG0 = 0; - CDROM_REG1 = CDL_SETLOC; - uint32_t errorTime = waitCDRomIRQ(); - uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; - uint8_t response[16]; - uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; - CDROM_REG0 = 1; - uint8_t cause1b = CDROM_REG3_UC; - - cester_assert_uint_eq(5, cause1); - cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); - cester_assert_uint_eq(3, response[0]); - cester_assert_uint_eq(32, response[1]); - cester_assert_uint_eq(2, responseSize); - // we seem to consistently get ~1ms with a pretty tight margin - // of error from this test, but let's still give it some slack. - cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); - ramsyscall_printf("Invalid setloc with no args, errored in %ius\n", errorTime); -) +#include "cdlinit.c" +#include "cdlsetloc.c" From 6b2e92d2027fc8b0225dedef9db8c2a0ce155a6d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 20:21:25 -0800 Subject: [PATCH 032/185] Refactoring response. --- src/core/cdrom.cc | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 5bcb40da6..e61a61039 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -23,6 +23,8 @@ #include "core/cdrom.h" +#include + #include "cdrom/iec-60908b.h" #include "cdrom/iso9660-reader.h" #include "core/debug.h" @@ -34,7 +36,7 @@ namespace { -using namespace std::chrono_literals; +using namespace std::literals; class CDRomImpl final : public PCSX::CDRom { enum Commands { @@ -132,6 +134,12 @@ class CDRomImpl final : public PCSX::CDRom { void clearIRQ() { psxHu32ref(0x1070) &= SWAP_LE32(~uint32_t(4)); } + void setResponse(std::string_view response) { + m_responseFIFOSize = response.size(); + m_responseFIFOIndex = 0; + std::copy(response.begin(), response.end(), m_responseFIFO); + } + uint8_t read0() override { uint8_t v01 = m_registerIndex & 3; uint8_t adpcmPlaying = 0; @@ -278,7 +286,6 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: got ack\n"); if (m_waitingAck) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: was waiting on ack\n"); - using namespace std::chrono_literals; m_waitingAck = false; schedule(350us); } @@ -350,14 +357,9 @@ class CDRomImpl final : public PCSX::CDRom { if ((m_paramFIFOSize == 3) && (maybeMSF.has_value())) { m_cause = Cause::Acknowledge; m_seekPosition = maybeMSF.value(); - m_responseFIFOSize = 1; - m_responseFIFOIndex = 0; - m_responseFIFO[0] = 2; + setResponse("\x02"sv); } else { - m_responseFIFOSize = 2; - m_responseFIFOIndex = 0; - m_responseFIFO[0] = 3; - m_responseFIFO[1] = 32; + setResponse("\x03\x20"sv); m_cause = Cause::Error; } m_paramFIFOSize = 0; @@ -388,9 +390,7 @@ class CDRomImpl final : public PCSX::CDRom { case 1: m_cause = Cause::Acknowledge; m_state = 2; - m_responseFIFOSize = 1; - m_responseFIFOIndex = 0; - m_responseFIFO[0] = 2; + setResponse("\x02"sv); triggerIRQ(); schedule(120ms); break; @@ -404,9 +404,7 @@ class CDRomImpl final : public PCSX::CDRom { case 3: m_cause = Cause::Complete; m_state = 0; - m_responseFIFOSize = 1; - m_responseFIFOIndex = 0; - m_responseFIFO[0] = 2; + setResponse("\x02"sv); m_command = 0; triggerIRQ(); break; @@ -414,10 +412,7 @@ class CDRomImpl final : public PCSX::CDRom { m_cause = Cause::Error; m_state = 0; m_paramFIFOSize = 0; - m_responseFIFOSize = 2; - m_responseFIFOIndex = 0; - m_responseFIFO[0] = 3; - m_responseFIFO[1] = 32; + setResponse("\x03\x20"sv); m_command = 0; triggerIRQ(); } From 36658365eb8fa7d390566ed9fbfa9320ac40a753 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 20:39:17 -0800 Subject: [PATCH 033/185] Adding a README for the cdrom tests. --- src/mips/tests/cdrom/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/mips/tests/cdrom/README.md diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md new file mode 100644 index 000000000..bdfa5dd20 --- /dev/null +++ b/src/mips/tests/cdrom/README.md @@ -0,0 +1,9 @@ +# CDRom tests + +This directory contains tests for the CDRom controller of the PS1. They are assuming that there is a CD inserted in the drive, and the lid is closed. At the moment, they do not rely on a certain CD, but they will in the future. + +The tests are written in C, and are compiled using the [MIPS GCC toolchain](../../psyqo/GETTING_STARTED.md#the-toolchain). The tests are compiled using the `make` command, and the resulting binary needs to be run on systems that have an ANSI console connected. + +The tests are checking two things: proper results from the CDRom controller, and approximate timings. The former are exact value checks, and will always reproduce properly on the real hardware. The latter are approximate value checks, and will usually only reproduce properly on the real hardware if the CD is inserted in the drive, the lid is closed, and the drive has been settled for a few seconds, but may still be flaky on the real hardware. + +The code is commented to explain what is being tested, and why. The tests are also written to be as self-contained as possible, so that they can be easily copied and modified to test other things. From e188c084aeabe10e42a5419ae4f6b6c2bd268860 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 21:23:38 -0800 Subject: [PATCH 034/185] Adding setloc multi test, and helper. --- src/mips/tests/cdrom/cdlsetloc.c | 60 ++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cester-hw.c | 20 +++++++++++ 2 files changed, 80 insertions(+) diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index 947cf4f33..48ffe5c08 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -87,3 +87,63 @@ CESTER_TEST(cdlSetLocNoArgs, test_instances, cester_assert_uint_lt(errorTime, 1500); ramsyscall_printf("Invalid setloc with no args, errored in %ius\n", errorTime); ) + +CESTER_TEST(cdlSetLocMultiple, test_instances, + int resetDone = resetCDRom(); + uint8_t cause; + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 2; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t time1 = waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) { + cester_assert_uint_eq(3, cause); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0x99; + CDROM_REG2 = 0x59; + CDROM_REG2 = 0x74; + CDROM_REG1 = CDL_SETLOC; + uint32_t time2 = waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) { + cester_assert_uint_eq(3, cause); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0x50; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t time3 = waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) { + cester_assert_uint_eq(3, cause); + return; + } + + // Setloc is only changing an internal state. + // Its response time is very fast, and won't + // vary regardless of the location. + cester_assert_uint_ge(time1, 500); + cester_assert_uint_lt(time1, 2000); + cester_assert_uint_ge(time2, 500); + cester_assert_uint_lt(time2, 2000); + cester_assert_uint_ge(time3, 500); + cester_assert_uint_lt(time3, 2000); + ramsyscall_printf("Multiple setloc to 00:02:00, complete in %ius, %ius, %ius\n", time1, time2, time3); +) diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index bddb92181..5ae1985f3 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -114,6 +114,26 @@ CESTER_BODY( IMASK = imask; return 1; } + + static int setLoc(uint8_t minute, uint8_t second, uint8_t frame) { + uint32_t imask = IMASK; + uint8_t cause; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = minute; + CDROM_REG2 = second; + CDROM_REG2 = frame; + CDROM_REG1 = CDL_SETLOC; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 2) return 0; + + IMASK = imask; + return 1; + } ) CESTER_BEFORE_ALL(cpu_tests, From 07c9be48ea8c4ccc70d25b8ea61cb5fb111ab29b Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 21:36:16 -0800 Subject: [PATCH 035/185] Adding cdrom test in pcsxrunner. --- tests/pcsxrunner/cdrom.cc | 35 +++++++++++++++++++ .../tests/pcsxrunner/pcsxrunner.vcxproj | 1 + .../pcsxrunner/pcsxrunner.vcxproj.filters | 3 ++ 3 files changed, 39 insertions(+) create mode 100644 tests/pcsxrunner/cdrom.cc diff --git a/tests/pcsxrunner/cdrom.cc b/tests/pcsxrunner/cdrom.cc new file mode 100644 index 000000000..94a4de127 --- /dev/null +++ b/tests/pcsxrunner/cdrom.cc @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright (C) 2022 PCSX-Redux authors * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + ***************************************************************************/ + +#include "gtest/gtest.h" +#include "main/main.h" + +TEST(cdrom, Interpreter) { + MainInvoker invoker("-run", "-stdout", "-bios", "src/mips/openbios/openbios.bin", "-testmode", "-interpreter", + "-loadexe", "src/mips/tests/cdrom/cdrom.ps-exe"); + int ret = invoker.invoke(); + EXPECT_EQ(ret, 0); +} + +TEST(cdrom, Dynarec) { + MainInvoker invoker("-run", "-stdout", "-bios", "src/mips/openbios/openbios.bin", "-testmode", "-dynarec", + "-loadexe", "src/mips/tests/cdrom/cdrom.ps-exe"); + int ret = invoker.invoke(); + EXPECT_EQ(ret, 0); +} \ No newline at end of file diff --git a/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj b/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj index c345feb79..07345c293 100644 --- a/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj +++ b/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj @@ -378,6 +378,7 @@ + diff --git a/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj.filters b/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj.filters index e4da268aa..3bfa94813 100644 --- a/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj.filters +++ b/vsprojects/tests/pcsxrunner/pcsxrunner.vcxproj.filters @@ -33,6 +33,9 @@ Source Files + + Source Files + From f6c6ccb3bf321dce9e88ebf92df6ed9d569f22ee Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 22:14:09 -0800 Subject: [PATCH 036/185] Trying to increase hardware timing accuracy. --- src/mips/tests/cdrom/cester-hw.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index 5ae1985f3..f875fc6fc 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -49,13 +49,25 @@ CESTER_BODY( } static inline void initializeTime() { - s_lastHSyncCounter = COUNTERS[1].value; + while (1) { + uint32_t init = COUNTERS[1].value; + uint32_t counter; + while ((counter = COUNTERS[1].value) == init); + if (counter != COUNTERS[1].value) continue; + s_lastHSyncCounter = counter; + break; + } s_currentTime = 0; } static inline uint32_t updateTime() { uint32_t lastHSyncCounter = s_lastHSyncCounter; - uint32_t hsyncCounter = COUNTERS[1].value; + uint32_t hsyncCounter; + while (1) { + hsyncCounter = COUNTERS[1].value; + if (hsyncCounter != COUNTERS[1].value) continue; + break; + } if (hsyncCounter < lastHSyncCounter) { hsyncCounter += 0x10000; } From 774d890f5f87161e963c0c76482a769841b230e3 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 22:14:56 -0800 Subject: [PATCH 037/185] Adding more info on readme. --- src/mips/tests/cdrom/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index bdfa5dd20..8a501e5f5 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -7,3 +7,7 @@ The tests are written in C, and are compiled using the [MIPS GCC toolchain](../. The tests are checking two things: proper results from the CDRom controller, and approximate timings. The former are exact value checks, and will always reproduce properly on the real hardware. The latter are approximate value checks, and will usually only reproduce properly on the real hardware if the CD is inserted in the drive, the lid is closed, and the drive has been settled for a few seconds, but may still be flaky on the real hardware. The code is commented to explain what is being tested, and why. The tests are also written to be as self-contained as possible, so that they can be easily copied and modified to test other things. + +All in all, these tests are overdoing it in terms of state and feature tests, and over aggressive. PS1 games most definitely do not need this level of accuracy, but this controller is so finicky that it is better to be safe than sorry. An emulator able to pass these tests ought to be able to run anything, as long as the main CPU timings are somewhat accurate. + +A word on timings: the timings are measured using the hblank timer, which is usually pretty easy to get right in terms of accuracy. However, many games will have busy wait loop when talking to the controller, or race conditions between sending commands. This means that if the CPU runs too slow or too quickly, bugs will surface. If the emulator is passing the timing tests, but games are failing, it is likely that the CPU emulation speed accuracy is at fault here, not the controller's. From 46f0d3e0e54921ac3665c5e298d247489587256d Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 22:27:45 -0800 Subject: [PATCH 038/185] Adding more invalid setloc tests. --- src/mips/tests/cdrom/cdlsetloc.c | 81 ++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index 48ffe5c08..55575cba4 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -52,9 +52,10 @@ CESTER_TEST(cdlSetLoc, test_instances, cester_assert_uint_eq(0x18, stat2); cester_assert_uint_eq(2, response[0]); cester_assert_uint_eq(1, responseSize); - // Typical value seems to be around 1ms. + // Typical value seems to be around 1ms, but has + // been seen to spike high from time to time. cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 2000); + cester_assert_uint_lt(completeTime, 6500); ramsyscall_printf("Basic setloc to 00:02:00, complete in %ius\n", completeTime); ) @@ -82,9 +83,8 @@ CESTER_TEST(cdlSetLocNoArgs, test_instances, cester_assert_uint_eq(3, response[0]); cester_assert_uint_eq(32, response[1]); cester_assert_uint_eq(2, responseSize); - // Typical value seems to be around 1ms. cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 6500); ramsyscall_printf("Invalid setloc with no args, errored in %ius\n", errorTime); ) @@ -138,12 +138,77 @@ CESTER_TEST(cdlSetLocMultiple, test_instances, // Setloc is only changing an internal state. // Its response time is very fast, and won't - // vary regardless of the location. + // vary regardless of the location, but can + // still spike to 6ms from time to time. cester_assert_uint_ge(time1, 500); - cester_assert_uint_lt(time1, 2000); + cester_assert_uint_lt(time1, 6500); cester_assert_uint_ge(time2, 500); - cester_assert_uint_lt(time2, 2000); + cester_assert_uint_lt(time2, 6500); cester_assert_uint_ge(time3, 500); - cester_assert_uint_lt(time3, 2000); + cester_assert_uint_lt(time3, 6500); ramsyscall_printf("Multiple setloc to 00:02:00, complete in %ius, %ius, %ius\n", time1, time2, time3); ) + +CESTER_TEST(cdlSetLocInvalid1, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 2; + CDROM_REG2 = 0x2a; + CDROM_REG1 = CDL_SETLOC; + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(16, response[1]); + cester_assert_uint_eq(2, responseSize); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 6500); + ramsyscall_printf("Invalid setloc to 00:02:2a, errored in %ius\n", errorTime); +) + +CESTER_TEST(cdlSetLocInvalid2, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 2; + CDROM_REG2 = 0x79; + CDROM_REG1 = CDL_SETLOC; + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(16, response[1]); + cester_assert_uint_eq(2, responseSize); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 6500); + ramsyscall_printf("Invalid setloc to 00:02:79, errored in %ius\n", errorTime); +) From 526e3e7e4f55c8050a00fa0ca2b5472381b117b1 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 22 Dec 2022 22:32:39 -0800 Subject: [PATCH 039/185] Adding more invalid setloc tests. --- src/mips/tests/cdrom/cdlsetloc.c | 67 ++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index 55575cba4..ef499a61a 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -212,3 +212,70 @@ CESTER_TEST(cdlSetLocInvalid2, test_instances, cester_assert_uint_lt(errorTime, 6500); ramsyscall_printf("Invalid setloc to 00:02:79, errored in %ius\n", errorTime); ) + +CESTER_TEST(cdlSetLocTooManyArgs, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 2; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(32, response[1]); + cester_assert_uint_eq(2, responseSize); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 6500); + ramsyscall_printf("Invalid setloc with too many args, errored in %ius\n", errorTime); +) + +CESTER_TEST(cdlSetLocTooManyArgsAndInvalid, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 2; + CDROM_REG2 = 0x79; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SETLOC; + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(32, response[1]); + cester_assert_uint_eq(2, responseSize); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 6500); + ramsyscall_printf("Invalid setloc with too many invalid args, errored in %ius\n", errorTime); +) + From ed647683fe35ce8f8484f289aa3f4c6377caaa3d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 22:36:29 -0800 Subject: [PATCH 040/185] Adjusting code to make test pass. --- src/core/cdrom.cc | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index e61a61039..e7f06fe53 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -348,19 +348,20 @@ class CDRomImpl final : public PCSX::CDRom { schedule(1ms); break; case 1: { - // TODO: Verify that the command is aborted if - // these parameters are indeed wrong. - // Also probably should error out if no disc or + // TODO: probably should error out if no disc or // lid open? // What happens when issued during Read / Play? auto maybeMSF = getMSF(m_paramFIFO); if ((m_paramFIFOSize == 3) && (maybeMSF.has_value())) { + setResponse("\x02"sv); m_cause = Cause::Acknowledge; m_seekPosition = maybeMSF.value(); - setResponse("\x02"sv); - } else { + } else if (m_paramFIFOSize != 3) { setResponse("\x03\x20"sv); m_cause = Cause::Error; + } else { + setResponse("\x03\x10"sv); + m_cause = Cause::Error; } m_paramFIFOSize = 0; m_state = 0; From 9c28ac5c0fbb553096c440f71888bd6a9ad7e178 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 22 Dec 2022 22:36:42 -0800 Subject: [PATCH 041/185] Adding machine type blurb. --- src/mips/tests/cdrom/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index 8a501e5f5..918779140 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -6,6 +6,8 @@ The tests are written in C, and are compiled using the [MIPS GCC toolchain](../. The tests are checking two things: proper results from the CDRom controller, and approximate timings. The former are exact value checks, and will always reproduce properly on the real hardware. The latter are approximate value checks, and will usually only reproduce properly on the real hardware if the CD is inserted in the drive, the lid is closed, and the drive has been settled for a few seconds, but may still be flaky on the real hardware. +The tests are currently being run on a 9001 machine for its real hardware routine checks, with occasional tests being run on a wider range of hardware. + The code is commented to explain what is being tested, and why. The tests are also written to be as self-contained as possible, so that they can be easily copied and modified to test other things. All in all, these tests are overdoing it in terms of state and feature tests, and over aggressive. PS1 games most definitely do not need this level of accuracy, but this controller is so finicky that it is better to be safe than sorry. An emulator able to pass these tests ought to be able to run anything, as long as the main CPU timings are somewhat accurate. From f43d41beda26d10d0076811e3bfc659faef8d8d4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 16:34:12 -0800 Subject: [PATCH 042/185] Adding test iso creation script. --- src/mips/tests/cdrom/create-test-iso.lua | 120 +++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 src/mips/tests/cdrom/create-test-iso.lua diff --git a/src/mips/tests/cdrom/create-test-iso.lua b/src/mips/tests/cdrom/create-test-iso.lua new file mode 100644 index 000000000..f7ec0c2bc --- /dev/null +++ b/src/mips/tests/cdrom/create-test-iso.lua @@ -0,0 +1,120 @@ +-- Copyright (C) 2022 PCSX-Redux authors +-- +-- This program is free software; you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation; either version 2 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; if not, write to the +-- Free Software Foundation, Inc., +-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +-- This script creates a test ISO image for the CDROM unit tests. + +local uniromDisc = PCSX.getCurrentIso() +local uniromDiscReader = uniromDisc:createReader() +local uniromFile = uniromDiscReader:open('UNIROM_B.EXE;1') +local licenseFile = uniromDisc:open(0, 2352 * 16, 'RAW') +local iso = PCSX.isoBuilder(Support.File.open('test.bin', 'TRUNCATE')) +iso:writeLicense(licenseFile) + +local b = Support.NewLuaBuffer(2352) +ffi.fill(b.data, 2352) +b:resize(2048) + +local pvd = Support.File.buffer() +pvd:writeAt(b, 0) +pvd:writeU8At(1, 0) +pvd:writeAt('CD001', 1) +pvd:writeU32At(1, 132) +pvd:writeU32At(17, 140) +pvd:writeU32At(18, 158) + +local pt = Support.File.buffer() +pt:writeAt(b, 0) +pt:writeU8At(1, 0) +pt:writeU8At(18, 2) +pt:writeU8At(1, 6) + +local root = Support.File.buffer() +root:writeAt(b, 0) +root:writeU8At(42, 0) +root:writeU32At(19, 2) +root:writeU32At(uniromFile:size(), 10) +root:writeU8At(9, 32) +root:writeAt('PSX.EXE;1', 33) + +pvd:read(b) +iso:writeSector(b) +pt:read(b) +iso:writeSector(b) +root:read(b) +iso:writeSector(b) + +local count = 19 +while not uniromFile:eof() do + uniromFile:read(b) + iso:writeSector(b) + count = count + 1 +end + +ffi.fill(b.data, 2048) +for i = count, 70 * 60 * 75 - 1 do + b[0] = bit.band(i, 0xff) + b[1] = bit.band(bit.rshift(i, 8), 0xff) + b[2] = bit.band(bit.rshift(i, 16), 0xff) + iso:writeSector(b) +end + +b:resize(2352) +local audioTrack = Support.File.open('test-t2.bin', 'TRUNCATE') +for i = 1, 75 * 5 do + audioTrack:write(b) +end +local audioTrack = Support.File.open('test-t3.bin', 'TRUNCATE') +for i = 1, 75 * 5 + 15 do + audioTrack:write(b) +end +local audioTrack = Support.File.open('test-t4.bin', 'TRUNCATE') +for i = 1, 75 * 5 + 15 do + audioTrack:write(b) +end +local audioTrack = Support.File.open('test-t5.bin', 'TRUNCATE') +for i = 1, 75 * 5 + 15 do + audioTrack:write(b) +end +local audioTrack = Support.File.open('test-t6.bin', 'TRUNCATE') +for i = 1, 75 * 5 + 15 do + audioTrack:write(b) +end + +local cue = Support.File.open('test.cue', 'TRUNCATE') +cue:write('FILE "test.bin" BINARY\n') +cue:write(' TRACK 01 MODE1/2352\n') +cue:write(' INDEX 01 00:00:00\n') +cue:write('FILE "test-t2.bin" BINARY\n') +cue:write(' TRACK 02 AUDIO\n') +cue:write(' INDEX 01 00:00:00\n') +cue:write('FILE "test-t3.bin" BINARY\n') +cue:write(' TRACK 03 AUDIO\n') +cue:write(' INDEX 01 00:00:00\n') +cue:write('FILE "test-t4.bin" BINARY\n') +cue:write(' TRACK 04 AUDIO\n') +cue:write(' INDEX 00 00:00:00\n') +cue:write(' INDEX 01 00:02:00\n') +cue:write('FILE "test-t5.bin" BINARY\n') +cue:write(' TRACK 05 AUDIO\n') +cue:write(' INDEX 00 00:00:00\n') +cue:write(' INDEX 01 00:02:45\n') +cue:write('FILE "test-t6.bin" BINARY\n') +cue:write(' TRACK 06 AUDIO\n') +cue:write(' INDEX 00 00:00:00\n') +cue:write(' INDEX 01 00:02:00\n') + +PCSX.quit() From d2e1bbc33ffaf1d0645d0b2910783a5f4285ad97 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 16:50:42 -0800 Subject: [PATCH 043/185] Adding readme section about test iso creation tool. --- src/mips/tests/cdrom/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index 918779140..088d266ce 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -1,6 +1,14 @@ # CDRom tests -This directory contains tests for the CDRom controller of the PS1. They are assuming that there is a CD inserted in the drive, and the lid is closed. At the moment, they do not rely on a certain CD, but they will in the future. +This directory contains tests for the CDRom controller of the PS1. They are assuming that there is a CD inserted in the drive, and the lid is closed. The tests require a somewhat specific iso to be mounted. The iso can be created using the `create-test-iso.lua` script. PCSX-Redux itself is the interpreter for this script. It also requires a copy of the [Unirom iso](https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases/) to be present. + +The script can be run using the following command: + +```bash +pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC.bin -exec "dofile 'create-test-iso.lua'" +``` + +This will emit a `test.cue` file, and multiple corresponding tracks. The data track will contain Unirom itself, for potentially booting on a retail machine and be able to upload the tests to the machine using [`nops`](https://github.com/JonathanDotCel/NOTPSXSerial). The tests are written in C, and are compiled using the [MIPS GCC toolchain](../../psyqo/GETTING_STARTED.md#the-toolchain). The tests are compiled using the `make` command, and the resulting binary needs to be run on systems that have an ANSI console connected. From 207d78a883250fbdc4342198836f37211a187b18 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 16:58:03 -0800 Subject: [PATCH 044/185] Building test iso in the CI. --- .github/workflows/linux-build.yml | 11 ++++++++++- .github/workflows/linux-coverage.yml | 6 ++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 0a1f2dae2..6472784fb 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -23,8 +23,17 @@ jobs: token: ${{ secrets.GITHUB_TOKEN }} - run: | make -j 2 all pcsx-redux-tests + make -C src/mips/openbios -j 2 + cp src/mips/openbios/openbios.bin . + make -C src/mips/openbios clean make -C src/mips/tests -j 2 PCSX_TESTS=true - make -C src/mips/openbios -j 2 clean all + cp ./openbios.bin src/mips/openbios/ + - run: | + wget https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases/download/8.0.K/UNIROM_BOOTDISC_8.0.K.zip + - run: | + unzip UNIROM_BOOTDISC_8.0.K.zip + - run: | + xvfb-run catchsegv ./pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC_8.0.K.bin -exec "dofile 'src/mips/tests/cdrom/create-test-iso.lua'" - name: Packaging run: | git config --global --add safe.directory /__w/pcsx-redux/pcsx-redux diff --git a/.github/workflows/linux-coverage.yml b/.github/workflows/linux-coverage.yml index d9d48f35c..7c97dd65f 100644 --- a/.github/workflows/linux-coverage.yml +++ b/.github/workflows/linux-coverage.yml @@ -29,6 +29,12 @@ jobs: make -C src/mips/openbios clean make -C src/mips/tests -j 2 PCSX_TESTS=true cp ./openbios.bin src/mips/openbios/ + - run: | + wget https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases/download/8.0.K/UNIROM_BOOTDISC_8.0.K.zip + - run: | + unzip UNIROM_BOOTDISC_8.0.K.zip + - run: | + xvfb-run catchsegv ./pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC_8.0.K.bin -exec "dofile 'src/mips/tests/cdrom/create-test-iso.lua'" - name: Test run: | xvfb-run catchsegv ./pcsx-redux-tests From 2b0e6e5efeda67261e05feeb71501ba9b538e9c4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 17:20:10 -0800 Subject: [PATCH 045/185] Headless unzip. --- .github/workflows/linux-build.yml | 8 ++++---- .github/workflows/linux-coverage.yml | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index 6472784fb..c57c8681d 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -21,6 +21,10 @@ jobs: - uses: n1hility/cancel-previous-runs@v2 with: token: ${{ secrets.GITHUB_TOKEN }} + - run: | + wget https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases/download/8.0.K/UNIROM_BOOTDISC_8.0.K.zip + - run: | + unzip -o UNIROM_BOOTDISC_8.0.K.zip - run: | make -j 2 all pcsx-redux-tests make -C src/mips/openbios -j 2 @@ -28,10 +32,6 @@ jobs: make -C src/mips/openbios clean make -C src/mips/tests -j 2 PCSX_TESTS=true cp ./openbios.bin src/mips/openbios/ - - run: | - wget https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases/download/8.0.K/UNIROM_BOOTDISC_8.0.K.zip - - run: | - unzip UNIROM_BOOTDISC_8.0.K.zip - run: | xvfb-run catchsegv ./pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC_8.0.K.bin -exec "dofile 'src/mips/tests/cdrom/create-test-iso.lua'" - name: Packaging diff --git a/.github/workflows/linux-coverage.yml b/.github/workflows/linux-coverage.yml index 7c97dd65f..b90385c9e 100644 --- a/.github/workflows/linux-coverage.yml +++ b/.github/workflows/linux-coverage.yml @@ -22,6 +22,10 @@ jobs: - uses: n1hility/cancel-previous-runs@v2 with: token: ${{ secrets.GITHUB_TOKEN }} + - run: | + wget https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases/download/8.0.K/UNIROM_BOOTDISC_8.0.K.zip + - run: | + unzip -o UNIROM_BOOTDISC_8.0.K.zip - run: | make -j 2 all pcsx-redux-tests make -C src/mips/openbios -j 2 @@ -29,10 +33,6 @@ jobs: make -C src/mips/openbios clean make -C src/mips/tests -j 2 PCSX_TESTS=true cp ./openbios.bin src/mips/openbios/ - - run: | - wget https://github.com/JonathanDotCel/unirom8_bootdisc_and_firmware_for_ps1/releases/download/8.0.K/UNIROM_BOOTDISC_8.0.K.zip - - run: | - unzip UNIROM_BOOTDISC_8.0.K.zip - run: | xvfb-run catchsegv ./pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC_8.0.K.bin -exec "dofile 'src/mips/tests/cdrom/create-test-iso.lua'" - name: Test From c66a9a12e032c4cbfaad8526fffc3da85a1526f8 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 17:23:13 -0800 Subject: [PATCH 046/185] Fixing MacOS build. --- src/core/r3000a.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/r3000a.h b/src/core/r3000a.h index a23fbb14b..bb315ea9e 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -204,10 +204,10 @@ struct psxRegisters { uint8_t ICache_Code[0x1000]; uint32_t getFutureCycle(std::chrono::nanoseconds delay) const { return cycle + durationToCycles(delay); } std::chrono::nanoseconds getFutureTime(uint32_t futureCycle) const { - return std::chrono::nanoseconds(int32_t(futureCycle - cycle) * 1'000'000'000 / g_emulator->m_psxClockSpeed); + return std::chrono::nanoseconds(int32_t(futureCycle - cycle) * 1'000'000'000 / Emulator::m_psxClockSpeed); } static constexpr uint32_t durationToCycles(std::chrono::nanoseconds duration) { - return duration.count() * g_emulator->m_psxClockSpeed / 1'000'000'000; + return duration.count() * Emulator::m_psxClockSpeed / 1'000'000'000; } }; From 9f46a6ec31cc6ca3dc4cce2cf9839774e707e571 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 21:18:28 -0800 Subject: [PATCH 047/185] Splitting openbios & tests builds. --- .github/workflows/linux-build.yml | 11 ++++++----- .github/workflows/linux-coverage.yml | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linux-build.yml b/.github/workflows/linux-build.yml index c57c8681d..e0383a4f8 100644 --- a/.github/workflows/linux-build.yml +++ b/.github/workflows/linux-build.yml @@ -29,11 +29,6 @@ jobs: make -j 2 all pcsx-redux-tests make -C src/mips/openbios -j 2 cp src/mips/openbios/openbios.bin . - make -C src/mips/openbios clean - make -C src/mips/tests -j 2 PCSX_TESTS=true - cp ./openbios.bin src/mips/openbios/ - - run: | - xvfb-run catchsegv ./pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC_8.0.K.bin -exec "dofile 'src/mips/tests/cdrom/create-test-iso.lua'" - name: Packaging run: | git config --global --add safe.directory /__w/pcsx-redux/pcsx-redux @@ -53,6 +48,12 @@ jobs: echo ' ]' >> AppDir/usr/share/pcsx-redux/resources/version.json echo '}' >> AppDir/usr/share/pcsx-redux/resources/version.json appimage-builder --skip-tests + - run: | + make -C src/mips/openbios clean + make -C src/mips/tests -j 2 PCSX_TESTS=true + cp ./openbios.bin src/mips/openbios/ + - run: | + xvfb-run catchsegv ./pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC_8.0.K.bin -exec "dofile 'src/mips/tests/cdrom/create-test-iso.lua'" - name: Test run: | export GTEST_OUTPUT=xml:${TEST_RESULTS}/ diff --git a/.github/workflows/linux-coverage.yml b/.github/workflows/linux-coverage.yml index b90385c9e..849dc55a5 100644 --- a/.github/workflows/linux-coverage.yml +++ b/.github/workflows/linux-coverage.yml @@ -30,6 +30,7 @@ jobs: make -j 2 all pcsx-redux-tests make -C src/mips/openbios -j 2 cp src/mips/openbios/openbios.bin . + - run: | make -C src/mips/openbios clean make -C src/mips/tests -j 2 PCSX_TESTS=true cp ./openbios.bin src/mips/openbios/ From 7885e8ecad5fc2c83afe4e93c68e5a56597fb7e0 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 23:00:38 -0800 Subject: [PATCH 048/185] Adding cdlSeek tests. --- src/mips/tests/cdrom/cdlseek.c | 90 ++++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdrom.c | 1 + 2 files changed, 91 insertions(+) create mode 100644 src/mips/tests/cdrom/cdlseek.c diff --git a/src/mips/tests/cdrom/cdlseek.c b/src/mips/tests/cdrom/cdlseek.c new file mode 100644 index 000000000..e8085d955 --- /dev/null +++ b/src/mips/tests/cdrom/cdlseek.c @@ -0,0 +1,90 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlSeekL, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setlocDone = setLoc(0, 2, 0); + + initializeTime(); + // wait 10ms for things to settle + while (updateTime() < 10000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKL; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t stat3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t stat4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, stat3); + cester_assert_uint_eq(0x18, stat4); + // Typical value seems to be around 750us. + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 1500); + // Typical value seems to be around 144ms. Of course, this is + // with a proper laser assy. + cester_assert_uint_ge(completeTime, 140000); + cester_assert_uint_lt(completeTime, 150000); + ramsyscall_printf("Basic seekL to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index b5e1340f1..085fdf808 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -37,4 +37,5 @@ SOFTWARE. #include "cester-hw.c" #include "cdlinit.c" +#include "cdlseek.c" #include "cdlsetloc.c" From 07e48202ee2a5913b60860b2f18ea43bf8745d6d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 23 Dec 2022 23:39:02 -0800 Subject: [PATCH 049/185] Adjusting timings a bit. --- src/mips/tests/cdrom/cdlseek.c | 67 +++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cdlseek.c b/src/mips/tests/cdrom/cdlseek.c index e8085d955..2d5d789e1 100644 --- a/src/mips/tests/cdrom/cdlseek.c +++ b/src/mips/tests/cdrom/cdlseek.c @@ -26,6 +26,69 @@ SOFTWARE. // clang-format off +CESTER_TEST(cdlSeekP, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setlocDone = setLoc(0, 2, 0); + + initializeTime(); + // wait 10ms for things to settle + while (updateTime() < 10000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t stat2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t stat3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t stat4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, stat1); + cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, stat3); + cester_assert_uint_eq(0x18, stat4); + // Typical value seems to be around 750us. + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 1500); + // Typical value seems to be around 105ms. Of course, this is + // with a proper laser assy. + cester_assert_uint_ge(completeTime, 100000); + cester_assert_uint_lt(completeTime, 110000); + ramsyscall_printf("Basic seekP to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) + CESTER_TEST(cdlSeekL, test_instance, uint32_t imask = IMASK; @@ -79,8 +142,8 @@ CESTER_TEST(cdlSeekL, test_instance, cester_assert_uint_eq(0x18, stat4); // Typical value seems to be around 750us. cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 1500); - // Typical value seems to be around 144ms. Of course, this is + cester_assert_uint_lt(ackTime, 2000); + // Typical value seems to be around 145ms. Of course, this is // with a proper laser assy. cester_assert_uint_ge(completeTime, 140000); cester_assert_uint_lt(completeTime, 150000); From c8f62273486627ee61eeefec1820fbd1540ff359 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 04:42:00 -0800 Subject: [PATCH 050/185] Adding getTD and getTN to LuaISO. --- src/core/isoffi.lua | 9 +++++++++ src/core/luaiso.cc | 12 ++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/core/isoffi.lua b/src/core/isoffi.lua index 424aebad1..4a9776cd0 100644 --- a/src/core/isoffi.lua +++ b/src/core/isoffi.lua @@ -28,6 +28,7 @@ enum SectorMode { typedef struct { char opaque[?]; } LuaIso; typedef struct { char opaque[?]; } IsoReader; +typedef struct { uint8_t m, s, f; } MSF; void deleteIso(LuaIso* wrapper); @@ -40,6 +41,8 @@ void deleteIsoReader(IsoReader* isoReader); bool isReaderFailed(IsoReader* reader); LuaFile* readerOpen(IsoReader* reader, const char* path); LuaFile* fileisoOpen(LuaIso* wrapper, uint32_t lba, uint32_t size, enum SectorMode mode); +uint32_t getIsoTN(LuaIso* wrapper); +MSF getIsoTD(LuaIso* wrapper, uint32_t tn); typedef struct { char opaque[?]; } ISO9660Builder; ISO9660Builder* createIsoBuilder(LuaFile* out); @@ -74,6 +77,12 @@ local function createIsoWrapper(wrapper) if mode == nil then mode = 'GUESS' end return Support.File._createFileWrapper(C.fileisoOpen(self._wrapper, lba, size, mode)) end, + getTD = function(self, tn) + return C.getIsoTD(self._wrapper, tn) + end, + getTN = function(self) + return C.getIsoTN(self._wrapper) + end, } return iso end diff --git a/src/core/luaiso.cc b/src/core/luaiso.cc index f09981bb4..ebbcb3403 100644 --- a/src/core/luaiso.cc +++ b/src/core/luaiso.cc @@ -23,6 +23,7 @@ #include "cdrom/cdriso.h" #include "cdrom/file.h" +#include "cdrom/iec-60908b.h" #include "cdrom/iso9660-builder.h" #include "cdrom/iso9660-reader.h" #include "core/cdrom.h" @@ -36,6 +37,10 @@ struct LuaIso { std::shared_ptr iso; }; +struct MSF { + uint8_t m, s, f; +}; + void deleteIso(LuaIso* wrapper) { delete wrapper; } bool isIsoFailed(LuaIso* wrapper) { return wrapper->iso->failed(); } LuaIso* getCurrentIso() { return new LuaIso(PCSX::g_emulator->m_cdrom->getIso()); } @@ -50,6 +55,11 @@ PCSX::LuaFFI::LuaFile* readerOpen(PCSX::ISO9660Reader* reader, const char* path) PCSX::LuaFFI::LuaFile* fileisoOpen(LuaIso* wrapper, uint32_t lba, uint32_t size, PCSX::SectorMode mode) { return new PCSX::LuaFFI::LuaFile(new PCSX::CDRIsoFile(wrapper->iso, lba, size, mode)); } +uint32_t getIsoTN(LuaIso* wrapper) { return wrapper->iso->getTN(); } +MSF getIsoTD(LuaIso* wrapper, uint32_t tn) { + auto ret = wrapper->iso->getTD(tn); + return {ret.m, ret.s, ret.f}; +} PCSX::ISO9660Builder* createIsoBuilder(PCSX::LuaFFI::LuaFile* wrapper) { return new PCSX::ISO9660Builder(wrapper->file); @@ -82,6 +92,8 @@ static void registerAllSymbols(PCSX::Lua L) { REGISTER(L, deleteIso); REGISTER(L, isIsoFailed); REGISTER(L, getCurrentIso); + REGISTER(L, getIsoTD); + REGISTER(L, getIsoTN); REGISTER(L, createIsoReader); REGISTER(L, deleteIsoReader); REGISTER(L, isReaderFailed); From ea0f273808e939aca77c09a68d39ba2d695a4b79 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 04:54:32 -0800 Subject: [PATCH 051/185] Derp. --- src/mips/tests/cdrom/create-test-iso.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/create-test-iso.lua b/src/mips/tests/cdrom/create-test-iso.lua index f7ec0c2bc..edba40f6c 100644 --- a/src/mips/tests/cdrom/create-test-iso.lua +++ b/src/mips/tests/cdrom/create-test-iso.lua @@ -96,7 +96,7 @@ end local cue = Support.File.open('test.cue', 'TRUNCATE') cue:write('FILE "test.bin" BINARY\n') -cue:write(' TRACK 01 MODE1/2352\n') +cue:write(' TRACK 01 MODE2/2352\n') cue:write(' INDEX 01 00:00:00\n') cue:write('FILE "test-t2.bin" BINARY\n') cue:write(' TRACK 02 AUDIO\n') From 93642e58b69d44038d9c30ff96c0e99a070b8b25 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 05:00:38 -0800 Subject: [PATCH 052/185] Making this a bit more readable. --- src/mips/tests/cdrom/create-test-iso.lua | 44 +++++++++++++----------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/mips/tests/cdrom/create-test-iso.lua b/src/mips/tests/cdrom/create-test-iso.lua index edba40f6c..1dbbb7d63 100644 --- a/src/mips/tests/cdrom/create-test-iso.lua +++ b/src/mips/tests/cdrom/create-test-iso.lua @@ -95,26 +95,28 @@ for i = 1, 75 * 5 + 15 do end local cue = Support.File.open('test.cue', 'TRUNCATE') -cue:write('FILE "test.bin" BINARY\n') -cue:write(' TRACK 01 MODE2/2352\n') -cue:write(' INDEX 01 00:00:00\n') -cue:write('FILE "test-t2.bin" BINARY\n') -cue:write(' TRACK 02 AUDIO\n') -cue:write(' INDEX 01 00:00:00\n') -cue:write('FILE "test-t3.bin" BINARY\n') -cue:write(' TRACK 03 AUDIO\n') -cue:write(' INDEX 01 00:00:00\n') -cue:write('FILE "test-t4.bin" BINARY\n') -cue:write(' TRACK 04 AUDIO\n') -cue:write(' INDEX 00 00:00:00\n') -cue:write(' INDEX 01 00:02:00\n') -cue:write('FILE "test-t5.bin" BINARY\n') -cue:write(' TRACK 05 AUDIO\n') -cue:write(' INDEX 00 00:00:00\n') -cue:write(' INDEX 01 00:02:45\n') -cue:write('FILE "test-t6.bin" BINARY\n') -cue:write(' TRACK 06 AUDIO\n') -cue:write(' INDEX 00 00:00:00\n') -cue:write(' INDEX 01 00:02:00\n') +cue:write([[ +FILE "test.bin" BINARY + TRACK 01 MODE2/2352 + INDEX 01 00:00:00 +FILE "test-t2.bin" BINARY + TRACK 02 AUDIO + INDEX 01 00:00:00 +FILE "test-t3.bin" BINARY + TRACK 03 AUDIO + INDEX 01 00:00:00 +FILE "test-t4.bin" BINARY + TRACK 04 AUDIO + INDEX 00 00:00:00 + INDEX 01 00:02:00 +FILE "test-t5.bin" BINARY + TRACK 05 AUDIO + INDEX 00 00:00:00 + INDEX 01 00:02:45 +FILE "test-t6.bin" BINARY + TRACK 06 AUDIO + INDEX 00 00:00:00 + INDEX 01 00:02:00 +]]) PCSX.quit() From 8699443b33f0b7ed0eb2f1d335c79581cba06107 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 05:01:14 -0800 Subject: [PATCH 053/185] Disabling these tests for now. --- src/mips/tests/cdrom/cdlseek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cdlseek.c b/src/mips/tests/cdrom/cdlseek.c index 2d5d789e1..39638e4be 100644 --- a/src/mips/tests/cdrom/cdlseek.c +++ b/src/mips/tests/cdrom/cdlseek.c @@ -26,7 +26,7 @@ SOFTWARE. // clang-format off -CESTER_TEST(cdlSeekP, test_instance, +CESTER_SKIP_TEST(cdlSeekP, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -89,7 +89,7 @@ CESTER_TEST(cdlSeekP, test_instance, IMASK = imask; ) -CESTER_TEST(cdlSeekL, test_instance, +CESTER_SKIP_TEST(cdlSeekL, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; From 9359b93fb3cf77157352be2874c49831af83d655 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 06:00:15 -0800 Subject: [PATCH 054/185] Adding some more commands and tests, factorizing a bit. --- src/core/cdrom.cc | 118 +++++++++++++++++++++++++++---- src/core/cdrom.h | 21 ++++-- src/mips/tests/cdrom/cdlgettn.c | 112 +++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdlinit.c | 53 +++++++++----- src/mips/tests/cdrom/cdlseek.c | 32 ++++----- src/mips/tests/cdrom/cdlsetloc.c | 48 ++++++------- src/mips/tests/cdrom/cdrom.c | 1 + 7 files changed, 309 insertions(+), 76 deletions(-) create mode 100644 src/mips/tests/cdrom/cdlgettn.c diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index e7f06fe53..95781caa3 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -41,7 +41,7 @@ using namespace std::literals; class CDRomImpl final : public PCSX::CDRom { enum Commands { CdlSync = 0, - CdlGetStat = 1, + CdlNop = 1, CdlSetLoc = 2, CdlPlay = 3, CdlForward = 4, @@ -135,9 +135,41 @@ class CDRomImpl final : public PCSX::CDRom { void clearIRQ() { psxHu32ref(0x1070) &= SWAP_LE32(~uint32_t(4)); } void setResponse(std::string_view response) { + std::copy(response.begin(), response.end(), m_responseFIFO); m_responseFIFOSize = response.size(); m_responseFIFOIndex = 0; - std::copy(response.begin(), response.end(), m_responseFIFO); + } + + void setResponse(uint8_t response) { + m_responseFIFO[0] = response; + m_responseFIFOSize = 1; + m_responseFIFOIndex = 0; + } + + void appendResponse(std::string_view response) { + std::copy(response.begin(), response.end(), m_responseFIFO + m_responseFIFOSize); + m_responseFIFOSize += response.size(); + } + + void appendResponse(uint8_t response) { m_responseFIFO[m_responseFIFOSize++] = response; } + + uint8_t getStatus() { + uint8_t v1 = m_motorOn ? 0x02 : 0; + uint8_t v4 = m_wasLidOpened ? 0x10 : 0; + if (!isLidOpen()) m_wasLidOpened = false; + uint8_t v567 = 0; + switch (m_status) { + case Status::READING_DATA: + v567 = 0x20; + break; + case Status::SEEKING: + v567 = 0x40; + break; + case Status::PLAYING_CDDA: + v567 = 0x80; + break; + } + return v1 | v4 | v567; } uint8_t read0() override { @@ -340,6 +372,30 @@ class CDRomImpl final : public PCSX::CDRom { (this->*handler)(); } + // Command 1. + void cdlNop() { + switch (m_state) { + case 0: + m_state = 1; + schedule(750us); + break; + case 1: { + if (m_paramFIFOSize == 0) { + setResponse(getStatus()); + m_cause = Cause::Acknowledge; + } else { + setResponse(getStatus() | 1); + appendResponse(0x20); + m_cause = Cause::Error; + } + m_paramFIFOSize = 0; + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + // Command 2. void cdlSetLoc() { switch (m_state) { @@ -353,14 +409,16 @@ class CDRomImpl final : public PCSX::CDRom { // What happens when issued during Read / Play? auto maybeMSF = getMSF(m_paramFIFO); if ((m_paramFIFOSize == 3) && (maybeMSF.has_value())) { - setResponse("\x02"sv); + setResponse(getStatus()); m_cause = Cause::Acknowledge; m_seekPosition = maybeMSF.value(); } else if (m_paramFIFOSize != 3) { - setResponse("\x03\x20"sv); + setResponse(getStatus() | 1); + appendResponse(0x20); m_cause = Cause::Error; } else { - setResponse("\x03\x10"sv); + setResponse(getStatus() | 1); + appendResponse(0x10); m_cause = Cause::Error; } m_paramFIFOSize = 0; @@ -384,6 +442,7 @@ class CDRomImpl final : public PCSX::CDRom { // TODO: figure out exactly the various states of the CD-Rom controller // that are being reset, and their value. m_state = 1; + m_motorOn = true; m_currentPosition.reset(); m_seekPosition.reset(); schedule(2ms); @@ -391,7 +450,7 @@ class CDRomImpl final : public PCSX::CDRom { case 1: m_cause = Cause::Acknowledge; m_state = 2; - setResponse("\x02"sv); + setResponse(getStatus()); triggerIRQ(); schedule(120ms); break; @@ -405,7 +464,7 @@ class CDRomImpl final : public PCSX::CDRom { case 3: m_cause = Cause::Complete; m_state = 0; - setResponse("\x02"sv); + setResponse(getStatus()); m_command = 0; triggerIRQ(); break; @@ -413,12 +472,41 @@ class CDRomImpl final : public PCSX::CDRom { m_cause = Cause::Error; m_state = 0; m_paramFIFOSize = 0; - setResponse("\x03\x20"sv); + setResponse(getStatus() | 1); + appendResponse(0x20); m_command = 0; triggerIRQ(); } } + // Command 19. + void cdlGetTN() { + switch (m_state) { + case 0: + m_state = 1; + schedule(750us); + break; + case 1: { + // TODO: probably should error out if no disc or + // lid open? + if (m_paramFIFOSize == 0) { + setResponse(getStatus()); + appendResponse(1); + appendResponse(m_iso->getTN()); + m_cause = Cause::Acknowledge; + } else { + setResponse(getStatus() | 1); + appendResponse(0x20); + m_cause = Cause::Error; + } + m_paramFIFOSize = 0; + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + void cdlUnk() { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command\n"); PCSX::g_system->pause(); @@ -428,7 +516,7 @@ class CDRomImpl final : public PCSX::CDRom { const CommandType c_commandsHandlers[31] { #if 0 - &CDRomImpl::cdlSync, &CDRomImpl::cdlGetStat, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlPlay, // 0 + &CDRomImpl::cdlSync, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlPlay, // 0 &CDRomImpl::cdlForward, &CDRomImpl::cdlBackward, &CDRomImpl::cdlReadN, &CDRomImpl::cdlStandby, // 4 &CDRomImpl::cdlStop, &CDRomImpl::cdlPause, &CDRomImpl::cdlInit, &CDRomImpl::cdlMute, // 8 &CDRomImpl::cdlDemute, &CDRomImpl::cdlSetFilter, &CDRomImpl::cdlSetMode, &CDRomImpl::cdlGetParam, // 12 @@ -437,11 +525,11 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 &CDRomImpl::cdlReset, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 #else - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 16 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlGetTN, // 16 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 28 @@ -568,13 +656,13 @@ void PCSX::CDRom::parseIso() { g_system->printf(_("CD-ROM EXE Name: %.255s\n"), exename); } -bool PCSX::CDRom::isLidOpened() { +bool PCSX::CDRom::isLidOpen() { if (m_lidCloseScheduled) { const uint32_t cycle = g_emulator->m_cpu->m_regs.cycle; if (((int32_t)(m_lidCloseAtCycles - cycle)) <= 0) { m_lidCloseScheduled = false; - m_lidOpened = false; + m_lidOpen = false; } } - return m_lidOpened; + return m_lidOpen; } diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 30c3949c8..b3c29d4cd 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -50,17 +50,19 @@ class CDRom { CDRom() : m_iso(new CDRIso()) {} virtual ~CDRom() {} static CDRom* factory(); - bool isLidOpened(); + bool isLidOpen(); void closeLid() { - m_lidOpened = false; + m_lidOpen = false; m_lidCloseScheduled = false; } void openLid() { - m_lidOpened = true; + m_lidOpen = true; + m_wasLidOpened = true; m_lidCloseScheduled = false; } void scheduleCloseLid() { - m_lidOpened = true; + m_lidOpen = true; + m_wasLidOpened = true; m_lidCloseScheduled = true; using namespace std::chrono_literals; m_lidCloseAtCycles = g_emulator->m_cpu->m_regs.getFutureCycle(1s); @@ -104,7 +106,8 @@ class CDRom { bool paramFIFOAvailable() { return m_paramFIFOSize != 16; } bool responseFIFOHasData() { return m_responseFIFOIndex != m_responseFIFOSize; } - bool m_lidOpened = false; + bool m_lidOpen = false; + bool m_wasLidOpened = false; bool m_lidCloseScheduled = false; uint32_t m_lidCloseAtCycles = 0; @@ -121,6 +124,14 @@ class CDRom { bool m_busy = false; bool m_gotAck = false; bool m_waitingAck = false; + bool m_motorOn = false; + enum class Status { + STOPPED, + READING_DATA, + SEEKING, + PLAYING_CDDA, + }; + Status m_status = Status::STOPPED; uint8_t m_state = 0; uint8_t m_command = 0; diff --git a/src/mips/tests/cdrom/cdlgettn.c b/src/mips/tests/cdrom/cdlgettn.c new file mode 100644 index 000000000..e0792b0e6 --- /dev/null +++ b/src/mips/tests/cdrom/cdlgettn.c @@ -0,0 +1,112 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlGetTN, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETTN; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, response1[1]); + cester_assert_uint_eq(6, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Typical value seems to be around 2ms, but varies a lot. + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 5000); + ramsyscall_printf("Basic getTN: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTNWithArgs, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_GETTN; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(32, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Typical value seems to be around 750us. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Basic getTN: errored in %ius\n", errorTime); + + IMASK = imask; +) diff --git a/src/mips/tests/cdrom/cdlinit.c b/src/mips/tests/cdrom/cdlinit.c index 41372b5f9..a55c725f6 100644 --- a/src/mips/tests/cdrom/cdlinit.c +++ b/src/mips/tests/cdrom/cdlinit.c @@ -42,19 +42,19 @@ CESTER_TEST(cdlInit, test_instance, uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response1[16]; uint8_t responseSize1 = readResponse(response1); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; uint32_t completeTime = waitCDRomIRQ() - ackTime; uint8_t cause2 = ackCDRomCause(); - uint8_t stat3 = CDROM_REG0 & ~3; + uint8_t ctrl3 = CDROM_REG0 & ~3; uint8_t response2[16]; uint8_t responseSize2 = readResponse(response2); - uint8_t stat4 = CDROM_REG0 & ~3; + uint8_t ctrl4 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause2b = CDROM_REG3_UC; @@ -66,10 +66,10 @@ CESTER_TEST(cdlInit, test_instance, cester_assert_uint_eq(1, responseSize1); cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); - cester_assert_uint_eq(0x38, stat3); - cester_assert_uint_eq(0x18, stat4); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); // Typical value seems to be around 2ms. cester_assert_uint_ge(ackTime, 800); cester_assert_uint_lt(ackTime, 5000); @@ -111,7 +111,7 @@ CESTER_TEST(cdlInitDelayed, test_instance, uint8_t cause1 = ackCDRomCause(); CDROM_REG1; - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; initializeTime(); @@ -119,15 +119,15 @@ CESTER_TEST(cdlInitDelayed, test_instance, uint32_t completeTime = waitCDRomIRQ(); uint8_t cause2 = ackCDRomCause(); CDROM_REG1; - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; cester_assert_false(gotIRQ); cester_assert_uint_ge(delayedTime, 500000); cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(2, cause2); - cester_assert_uint_eq(0x18, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x18, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); // This still takes about 2ms. cester_assert_uint_ge(ackTime, 800); cester_assert_uint_lt(ackTime, 5000); @@ -162,24 +162,45 @@ CESTER_TEST(cdlInitWithArgs, test_instance, uint32_t errorTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response1[16]; uint8_t responseSize1 = readResponse(response1); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(3, cause2); cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); cester_assert_uint_eq(3, response1[0]); cester_assert_uint_eq(32, response1[1]); cester_assert_uint_eq(2, responseSize1); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); // Typical value seems to be around 1ms. cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 2000); + // Typical value seems to be around 1.5ms. + cester_assert_uint_ge(ackTime, 1000); + cester_assert_uint_lt(ackTime, 2500); ramsyscall_printf("Initialization with args: CD-Rom controller errored, error in %ius\n", errorTime); + ramsyscall_printf("Initialization with args: requested status, ack in %ius\n", ackTime); IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlseek.c b/src/mips/tests/cdrom/cdlseek.c index 39638e4be..d4f60562f 100644 --- a/src/mips/tests/cdrom/cdlseek.c +++ b/src/mips/tests/cdrom/cdlseek.c @@ -49,19 +49,19 @@ CESTER_SKIP_TEST(cdlSeekP, test_instance, uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response1[16]; uint8_t responseSize1 = readResponse(response1); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; uint32_t completeTime = waitCDRomIRQ() - ackTime; uint8_t cause2 = ackCDRomCause(); - uint8_t stat3 = CDROM_REG0 & ~3; + uint8_t ctrl3 = CDROM_REG0 & ~3; uint8_t response2[16]; uint8_t responseSize2 = readResponse(response2); - uint8_t stat4 = CDROM_REG0 & ~3; + uint8_t ctrl4 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause2b = CDROM_REG3_UC; @@ -73,10 +73,10 @@ CESTER_SKIP_TEST(cdlSeekP, test_instance, cester_assert_uint_eq(1, responseSize1); cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); - cester_assert_uint_eq(0x38, stat3); - cester_assert_uint_eq(0x18, stat4); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); // Typical value seems to be around 750us. cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 1500); @@ -112,19 +112,19 @@ CESTER_SKIP_TEST(cdlSeekL, test_instance, uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response1[16]; uint8_t responseSize1 = readResponse(response1); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; uint32_t completeTime = waitCDRomIRQ() - ackTime; uint8_t cause2 = ackCDRomCause(); - uint8_t stat3 = CDROM_REG0 & ~3; + uint8_t ctrl3 = CDROM_REG0 & ~3; uint8_t response2[16]; uint8_t responseSize2 = readResponse(response2); - uint8_t stat4 = CDROM_REG0 & ~3; + uint8_t ctrl4 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause2b = CDROM_REG3_UC; @@ -136,10 +136,10 @@ CESTER_SKIP_TEST(cdlSeekL, test_instance, cester_assert_uint_eq(1, responseSize1); cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); - cester_assert_uint_eq(0x38, stat3); - cester_assert_uint_eq(0x18, stat4); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); // Typical value seems to be around 750us. cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 2000); diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index ef499a61a..4cc86aef7 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -39,17 +39,17 @@ CESTER_TEST(cdlSetLoc, test_instances, CDROM_REG1 = CDL_SETLOC; uint32_t completeTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(2, response[0]); cester_assert_uint_eq(1, responseSize); // Typical value seems to be around 1ms, but has @@ -69,17 +69,17 @@ CESTER_TEST(cdlSetLocNoArgs, test_instances, CDROM_REG1 = CDL_SETLOC; uint32_t errorTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); cester_assert_uint_eq(32, response[1]); cester_assert_uint_eq(2, responseSize); @@ -162,17 +162,17 @@ CESTER_TEST(cdlSetLocInvalid1, test_instances, CDROM_REG1 = CDL_SETLOC; uint32_t errorTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); cester_assert_uint_eq(16, response[1]); cester_assert_uint_eq(2, responseSize); @@ -194,17 +194,17 @@ CESTER_TEST(cdlSetLocInvalid2, test_instances, CDROM_REG1 = CDL_SETLOC; uint32_t errorTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); cester_assert_uint_eq(16, response[1]); cester_assert_uint_eq(2, responseSize); @@ -227,17 +227,17 @@ CESTER_TEST(cdlSetLocTooManyArgs, test_instances, CDROM_REG1 = CDL_SETLOC; uint32_t errorTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); cester_assert_uint_eq(32, response[1]); cester_assert_uint_eq(2, responseSize); @@ -260,17 +260,17 @@ CESTER_TEST(cdlSetLocTooManyArgsAndInvalid, test_instances, CDROM_REG1 = CDL_SETLOC; uint32_t errorTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); - uint8_t stat1 = CDROM_REG0 & ~3; + uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; uint8_t responseSize = readResponse(response); - uint8_t stat2 = CDROM_REG0 & ~3; + uint8_t ctrl2 = CDROM_REG0 & ~3; CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0x38, stat1); - cester_assert_uint_eq(0x18, stat2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); cester_assert_uint_eq(32, response[1]); cester_assert_uint_eq(2, responseSize); diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 085fdf808..7abbd5fe3 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -36,6 +36,7 @@ SOFTWARE. #include "exotic/cester.h" #include "cester-hw.c" +#include "cdlgettn.c" #include "cdlinit.c" #include "cdlseek.c" #include "cdlsetloc.c" From dc4353c6f3aaaf20ac878126489ad7e9f2f68959 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 09:36:21 -0800 Subject: [PATCH 055/185] Actually loading test iso in cdrom test. --- tests/pcsxrunner/cdrom.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/pcsxrunner/cdrom.cc b/tests/pcsxrunner/cdrom.cc index 94a4de127..989fae0c5 100644 --- a/tests/pcsxrunner/cdrom.cc +++ b/tests/pcsxrunner/cdrom.cc @@ -22,14 +22,14 @@ TEST(cdrom, Interpreter) { MainInvoker invoker("-run", "-stdout", "-bios", "src/mips/openbios/openbios.bin", "-testmode", "-interpreter", - "-loadexe", "src/mips/tests/cdrom/cdrom.ps-exe"); + "-iso", "test.cue", "-loadexe", "src/mips/tests/cdrom/cdrom.ps-exe"); int ret = invoker.invoke(); EXPECT_EQ(ret, 0); } TEST(cdrom, Dynarec) { - MainInvoker invoker("-run", "-stdout", "-bios", "src/mips/openbios/openbios.bin", "-testmode", "-dynarec", - "-loadexe", "src/mips/tests/cdrom/cdrom.ps-exe"); + MainInvoker invoker("-run", "-stdout", "-bios", "src/mips/openbios/openbios.bin", "-testmode", "-dynarec", "-iso", + "test.cue", "-loadexe", "src/mips/tests/cdrom/cdrom.ps-exe"); int ret = invoker.invoke(); EXPECT_EQ(ret, 0); } \ No newline at end of file From 6c708f933c67d569a0262098c0cbcaa97213a9bd Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 10:24:12 -0800 Subject: [PATCH 056/185] Removing some logs. --- src/core/cdrom.cc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 95781caa3..f20fe2ace 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -183,7 +183,6 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t ret = v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7; - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r0: %02x\n", ret); return ret; } @@ -194,7 +193,7 @@ class CDRomImpl final : public PCSX::CDRom { } else { ret = m_responseFIFO[m_responseFIFOIndex++]; } - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r1: %02x\n", ret); + return ret; } @@ -205,7 +204,7 @@ class CDRomImpl final : public PCSX::CDRom { } else { ret = m_dataFIFO[m_dataFIFOIndex++]; } - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r2: %02x\n", ret); + return ret; } @@ -221,7 +220,6 @@ class CDRomImpl final : public PCSX::CDRom { // cause // TODO: add bit 4 uint8_t ret = magic_enum::enum_integer(m_cause) | 0xe0; - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: read cause, returning %02x\n", ret); m_cause = Cause::None; return ret; } break; @@ -231,12 +229,10 @@ class CDRomImpl final : public PCSX::CDRom { } void write0(uint8_t value) override { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w0: %02x\n", value); m_registerIndex = value & 3; } void write1(uint8_t value) override { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1: %02x\n", value); switch (m_registerIndex) { case 0: { if (m_busy) { @@ -267,7 +263,6 @@ class CDRomImpl final : public PCSX::CDRom { } void write2(uint8_t value) override { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2: %02x\n", value); switch (m_registerIndex) { case 0: { if (paramFIFOAvailable()) m_paramFIFO[m_paramFIFOSize++] = value; @@ -296,7 +291,6 @@ class CDRomImpl final : public PCSX::CDRom { } void write3(uint8_t value) override { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3: %02x\n", value); switch (m_registerIndex) { case 0: { // ?? @@ -315,9 +309,7 @@ class CDRomImpl final : public PCSX::CDRom { ack = true; } if (ack) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: got ack\n"); if (m_waitingAck) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: was waiting on ack\n"); m_waitingAck = false; schedule(350us); } @@ -431,7 +423,6 @@ class CDRomImpl final : public PCSX::CDRom { // Command 10. void cdlInit() { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: cdlInit, state = %i\n", m_state); switch (m_state) { case 0: if (m_paramFIFOSize != 0) { From 199730c86afe24c9192962a39a3747b4ca9ba2cb Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 11:07:02 -0800 Subject: [PATCH 057/185] Factorizing more code. --- src/core/cdrom.cc | 80 +++++++++++++++++++++++------------------------ src/core/cdrom.h | 1 + 2 files changed, 40 insertions(+), 41 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index f20fe2ace..a5178d94f 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -105,8 +105,17 @@ class CDRomImpl final : public PCSX::CDRom { } void interrupt() override { + if (m_errorArgumentsCount) { + m_errorArgumentsCount = false; + m_cause = Cause::Error; + m_paramFIFOSize = 0; + m_command = 0; + setResponse(getStatus() | 1); + appendResponse(0x20); + triggerIRQ(); + return; + } auto handler = c_commandsHandlers[m_command]; - (this->*handler)(); } @@ -228,9 +237,7 @@ class CDRomImpl final : public PCSX::CDRom { return 0; } - void write0(uint8_t value) override { - m_registerIndex = value & 3; - } + void write0(uint8_t value) override { m_registerIndex = value & 3; } void write1(uint8_t value) override { switch (m_registerIndex) { @@ -357,10 +364,19 @@ class CDRomImpl final : public PCSX::CDRom { if (command > 30) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command\n"); PCSX::g_system->pause(); + return; } - auto handler = c_commandsHandlers[command]; + auto count = c_commandsArgumentsCount[command]; + if (count >= 0) { + if (m_paramFIFOSize != count) { + m_errorArgumentsCount = true; + schedule(750us); + return; + } + } + auto handler = c_commandsHandlers[command]; (this->*handler)(); } @@ -372,14 +388,8 @@ class CDRomImpl final : public PCSX::CDRom { schedule(750us); break; case 1: { - if (m_paramFIFOSize == 0) { - setResponse(getStatus()); - m_cause = Cause::Acknowledge; - } else { - setResponse(getStatus() | 1); - appendResponse(0x20); - m_cause = Cause::Error; - } + setResponse(getStatus()); + m_cause = Cause::Acknowledge; m_paramFIFOSize = 0; m_state = 0; m_command = 0; @@ -400,14 +410,10 @@ class CDRomImpl final : public PCSX::CDRom { // lid open? // What happens when issued during Read / Play? auto maybeMSF = getMSF(m_paramFIFO); - if ((m_paramFIFOSize == 3) && (maybeMSF.has_value())) { + if (maybeMSF.has_value()) { setResponse(getStatus()); m_cause = Cause::Acknowledge; m_seekPosition = maybeMSF.value(); - } else if (m_paramFIFOSize != 3) { - setResponse(getStatus() | 1); - appendResponse(0x20); - m_cause = Cause::Error; } else { setResponse(getStatus() | 1); appendResponse(0x10); @@ -425,11 +431,6 @@ class CDRomImpl final : public PCSX::CDRom { void cdlInit() { switch (m_state) { case 0: - if (m_paramFIFOSize != 0) { - m_state = 4; - schedule(1ms); - break; - } // TODO: figure out exactly the various states of the CD-Rom controller // that are being reset, and their value. m_state = 1; @@ -459,14 +460,6 @@ class CDRomImpl final : public PCSX::CDRom { m_command = 0; triggerIRQ(); break; - case 4: - m_cause = Cause::Error; - m_state = 0; - m_paramFIFOSize = 0; - setResponse(getStatus() | 1); - appendResponse(0x20); - m_command = 0; - triggerIRQ(); } } @@ -480,16 +473,10 @@ class CDRomImpl final : public PCSX::CDRom { case 1: { // TODO: probably should error out if no disc or // lid open? - if (m_paramFIFOSize == 0) { - setResponse(getStatus()); - appendResponse(1); - appendResponse(m_iso->getTN()); - m_cause = Cause::Acknowledge; - } else { - setResponse(getStatus() | 1); - appendResponse(0x20); - m_cause = Cause::Error; - } + setResponse(getStatus()); + appendResponse(1); + appendResponse(m_iso->getTN()); + m_cause = Cause::Acknowledge; m_paramFIFOSize = 0; m_state = 0; m_command = 0; @@ -527,6 +514,17 @@ class CDRomImpl final : public PCSX::CDRom { #endif }; + static constexpr int c_commandsArgumentsCount[31] = { + 0, 0, 3, -1, // 0 + 0, 0, 0, 0, // 4 + 0, 0, 0, 0, // 8 + 0, 2, 1, 0, // 12 + 0, 0, 1, 0, // 16 + 1, 0, 0, 0, // 20 + 0, -1, 0, 0, // 24 + 0, 0, 0, // 28 + }; + void logCDROM(uint8_t command) { uint32_t pc = PCSX::g_emulator->m_cpu->m_regs.pc; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index b3c29d4cd..a2fe2761d 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -121,6 +121,7 @@ class CDRom { uint8_t m_responseFIFOIndex = 0; uint8_t m_responseFIFOSize = 0; uint8_t m_registerIndex = 0; + bool m_errorArgumentsCount = false; bool m_busy = false; bool m_gotAck = false; bool m_waitingAck = false; From 68152289220487cb7482214f134f9b3fda0d4506 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 11:26:53 -0800 Subject: [PATCH 058/185] Tweaking timings, bumping number of test tracks to 25, adding invalid command test. --- src/core/cdrom.cc | 2 +- src/mips/tests/cdrom/cdlgettn.c | 4 +- src/mips/tests/cdrom/cdrom.c | 1 + src/mips/tests/cdrom/create-test-iso.lua | 21 ++++++-- src/mips/tests/cdrom/invalid.c | 67 ++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 8 deletions(-) create mode 100644 src/mips/tests/cdrom/invalid.c diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index a5178d94f..af5ee68be 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -468,7 +468,7 @@ class CDRomImpl final : public PCSX::CDRom { switch (m_state) { case 0: m_state = 1; - schedule(750us); + schedule(2ms); break; case 1: { // TODO: probably should error out if no disc or diff --git a/src/mips/tests/cdrom/cdlgettn.c b/src/mips/tests/cdrom/cdlgettn.c index e0792b0e6..8458b378e 100644 --- a/src/mips/tests/cdrom/cdlgettn.c +++ b/src/mips/tests/cdrom/cdlgettn.c @@ -55,13 +55,13 @@ CESTER_TEST(cdlGetTN, test_instance, cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(2, response1[0]); cester_assert_uint_eq(1, response1[1]); - cester_assert_uint_eq(6, response1[2]); + cester_assert_uint_eq(25, response1[2]); cester_assert_uint_eq(3, responseSize1); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); // Typical value seems to be around 2ms, but varies a lot. cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 5000); + cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTN: ack in %ius\n", ackTime); IMASK = imask; diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 7abbd5fe3..40cdcc959 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -40,3 +40,4 @@ SOFTWARE. #include "cdlinit.c" #include "cdlseek.c" #include "cdlsetloc.c" +#include "invalid.c" diff --git a/src/mips/tests/cdrom/create-test-iso.lua b/src/mips/tests/cdrom/create-test-iso.lua index 1dbbb7d63..6b0f1947e 100644 --- a/src/mips/tests/cdrom/create-test-iso.lua +++ b/src/mips/tests/cdrom/create-test-iso.lua @@ -73,23 +73,24 @@ for i = count, 70 * 60 * 75 - 1 do end b:resize(2352) -local audioTrack = Support.File.open('test-t2.bin', 'TRUNCATE') +local audioTrack +audioTrack = Support.File.open('test-t2.bin', 'TRUNCATE') for i = 1, 75 * 5 do audioTrack:write(b) end -local audioTrack = Support.File.open('test-t3.bin', 'TRUNCATE') +audioTrack = Support.File.open('test-t3.bin', 'TRUNCATE') for i = 1, 75 * 5 + 15 do audioTrack:write(b) end -local audioTrack = Support.File.open('test-t4.bin', 'TRUNCATE') +audioTrack = Support.File.open('test-t4.bin', 'TRUNCATE') for i = 1, 75 * 5 + 15 do audioTrack:write(b) end -local audioTrack = Support.File.open('test-t5.bin', 'TRUNCATE') +audioTrack = Support.File.open('test-t5.bin', 'TRUNCATE') for i = 1, 75 * 5 + 15 do audioTrack:write(b) end -local audioTrack = Support.File.open('test-t6.bin', 'TRUNCATE') +audioTrack = Support.File.open('test-t6.bin', 'TRUNCATE') for i = 1, 75 * 5 + 15 do audioTrack:write(b) end @@ -119,4 +120,14 @@ FILE "test-t6.bin" BINARY INDEX 01 00:02:00 ]]) +for i = 7, 25 do + audioTrack = Support.File.open(string.format('test-t%d.bin', i), 'TRUNCATE') + for j = 1, 75 * 5 + 15 do + audioTrack:write(b) + end + cue:write(string.format('FILE "test-t%d.bin" BINARY\n', i)) + cue:write(string.format(' TRACK %02d AUDIO\n', i)) + cue:write(' INDEX 01 00:02:00\n') +end + PCSX.quit() diff --git a/src/mips/tests/cdrom/invalid.c b/src/mips/tests/cdrom/invalid.c new file mode 100644 index 000000000..06b2799df --- /dev/null +++ b/src/mips/tests/cdrom/invalid.c @@ -0,0 +1,67 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(invalid0, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SYNC; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(64, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Typical value seems to be around 750us. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Basic getTN: errored in %ius\n", errorTime); + + IMASK = imask; +) From 4c90e92c1de74802e2d470ea7c74d6f3aedef842 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 11:27:48 -0800 Subject: [PATCH 059/185] Fixing GetTN. --- src/core/cdrom.cc | 2 +- src/mips/tests/cdrom/cdlgettn.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index af5ee68be..493a2dd76 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -475,7 +475,7 @@ class CDRomImpl final : public PCSX::CDRom { // lid open? setResponse(getStatus()); appendResponse(1); - appendResponse(m_iso->getTN()); + appendResponse(PCSX::IEC60908b::itob(m_iso->getTN())); m_cause = Cause::Acknowledge; m_paramFIFOSize = 0; m_state = 0; diff --git a/src/mips/tests/cdrom/cdlgettn.c b/src/mips/tests/cdrom/cdlgettn.c index 8458b378e..0ae658854 100644 --- a/src/mips/tests/cdrom/cdlgettn.c +++ b/src/mips/tests/cdrom/cdlgettn.c @@ -55,7 +55,7 @@ CESTER_TEST(cdlGetTN, test_instance, cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(2, response1[0]); cester_assert_uint_eq(1, response1[1]); - cester_assert_uint_eq(25, response1[2]); + cester_assert_uint_eq(0x25, response1[2]); cester_assert_uint_eq(3, responseSize1); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); From 9d43d7986c9d248ea35556c92fc7a7225149183a Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 11:38:02 -0800 Subject: [PATCH 060/185] Consistency. --- src/core/cdrom.cc | 7 ++++--- src/core/cdrom.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 493a2dd76..125b1594f 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -163,9 +163,10 @@ class CDRomImpl final : public PCSX::CDRom { void appendResponse(uint8_t response) { m_responseFIFO[m_responseFIFOSize++] = response; } uint8_t getStatus() { - uint8_t v1 = m_motorOn ? 0x02 : 0; + bool lidOpen = isLidOpen(); + uint8_t v1 = m_motorOn && !lidOpen ? 0x02 : 0; uint8_t v4 = m_wasLidOpened ? 0x10 : 0; - if (!isLidOpen()) m_wasLidOpened = false; + if (!lidOpen) m_wasLidOpened = false; uint8_t v567 = 0; switch (m_status) { case Status::READING_DATA: @@ -208,7 +209,7 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t read2() override { uint8_t ret = 0; - if (dataFIFOEmpty()) { + if (!dataFIFOHasData()) { ret = 0; } else { ret = m_dataFIFO[m_dataFIFOIndex++]; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index a2fe2761d..6c7a0a466 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -102,7 +102,7 @@ class CDRom { std::shared_ptr m_iso; friend SaveStates::SaveState SaveStates::constructSaveState(); - bool dataFIFOEmpty() { return m_dataFIFOIndex == m_dataFIFOSize; } + bool dataFIFOHasData() { return m_dataFIFOIndex != m_dataFIFOSize; } bool paramFIFOAvailable() { return m_paramFIFOSize != 16; } bool responseFIFOHasData() { return m_responseFIFOIndex != m_responseFIFOSize; } From a5fc9c6528433b0295073beca129930741f645d9 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 11:46:49 -0800 Subject: [PATCH 061/185] Making test pass and some minor adjustments. --- src/core/cdrom.cc | 22 ++++++++++++++++++++-- src/mips/tests/cdrom/cdlgettn.c | 2 +- src/mips/tests/cdrom/cdlinit.c | 2 +- src/mips/tests/cdrom/cdlsetloc.c | 10 +++++----- src/mips/tests/cdrom/invalid.c | 4 ++-- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 125b1594f..166318450 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -487,8 +487,26 @@ class CDRomImpl final : public PCSX::CDRom { } void cdlUnk() { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command\n"); - PCSX::g_system->pause(); + switch (m_state) { + case 0: + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command %i\n", m_command); + if (PCSX::g_emulator->settings.get() + .get()) { + PCSX::g_system->pause(); + } + m_state = 1; + schedule(750us); + break; + case 1: + setResponse(getStatus() | 1); + appendResponse(0x40); + m_cause = Cause::Error; + m_paramFIFOSize = 0; + m_state = 0; + m_command = 0; + triggerIRQ(); + break; + } } typedef void (CDRomImpl::*CommandType)(); diff --git a/src/mips/tests/cdrom/cdlgettn.c b/src/mips/tests/cdrom/cdlgettn.c index 0ae658854..84c050d4d 100644 --- a/src/mips/tests/cdrom/cdlgettn.c +++ b/src/mips/tests/cdrom/cdlgettn.c @@ -99,7 +99,7 @@ CESTER_TEST(cdlGetTNWithArgs, test_instance, cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(3, response1[0]); - cester_assert_uint_eq(32, response1[1]); + cester_assert_uint_eq(0x20, response1[1]); cester_assert_uint_eq(2, responseSize1); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); diff --git a/src/mips/tests/cdrom/cdlinit.c b/src/mips/tests/cdrom/cdlinit.c index a55c725f6..a3610b465 100644 --- a/src/mips/tests/cdrom/cdlinit.c +++ b/src/mips/tests/cdrom/cdlinit.c @@ -185,7 +185,7 @@ CESTER_TEST(cdlInitWithArgs, test_instance, cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(0xe0, cause2b); cester_assert_uint_eq(3, response1[0]); - cester_assert_uint_eq(32, response1[1]); + cester_assert_uint_eq(0x20, response1[1]); cester_assert_uint_eq(2, responseSize1); cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index 4cc86aef7..c642820ad 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -81,7 +81,7 @@ CESTER_TEST(cdlSetLocNoArgs, test_instances, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); - cester_assert_uint_eq(32, response[1]); + cester_assert_uint_eq(0x20, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 6500); @@ -174,7 +174,7 @@ CESTER_TEST(cdlSetLocInvalid1, test_instances, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); - cester_assert_uint_eq(16, response[1]); + cester_assert_uint_eq(0x10, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 6500); @@ -206,7 +206,7 @@ CESTER_TEST(cdlSetLocInvalid2, test_instances, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); - cester_assert_uint_eq(16, response[1]); + cester_assert_uint_eq(0x10, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 6500); @@ -239,7 +239,7 @@ CESTER_TEST(cdlSetLocTooManyArgs, test_instances, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); - cester_assert_uint_eq(32, response[1]); + cester_assert_uint_eq(0x20, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 6500); @@ -272,7 +272,7 @@ CESTER_TEST(cdlSetLocTooManyArgsAndInvalid, test_instances, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(3, response[0]); - cester_assert_uint_eq(32, response[1]); + cester_assert_uint_eq(0x20, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 6500); diff --git a/src/mips/tests/cdrom/invalid.c b/src/mips/tests/cdrom/invalid.c index 06b2799df..6990fa854 100644 --- a/src/mips/tests/cdrom/invalid.c +++ b/src/mips/tests/cdrom/invalid.c @@ -54,14 +54,14 @@ CESTER_TEST(invalid0, test_instance, cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(3, response1[0]); - cester_assert_uint_eq(64, response1[1]); + cester_assert_uint_eq(0x40, response1[1]); cester_assert_uint_eq(2, responseSize1); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); // Typical value seems to be around 750us. cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 1500); - ramsyscall_printf("Basic getTN: errored in %ius\n", errorTime); + ramsyscall_printf("Invalid command 0: errored in %ius\n", errorTime); IMASK = imask; ) From 758b27711ea051e92d097d0256c1820d01341982 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 12:08:53 -0800 Subject: [PATCH 062/185] Adding getTD test. --- src/mips/tests/cdrom/cdlgettd.c | 109 ++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdrom.c | 1 + 2 files changed, 110 insertions(+) create mode 100644 src/mips/tests/cdrom/cdlgettd.c diff --git a/src/mips/tests/cdrom/cdlgettd.c b/src/mips/tests/cdrom/cdlgettd.c new file mode 100644 index 000000000..96c402a8f --- /dev/null +++ b/src/mips/tests/cdrom/cdlgettd.c @@ -0,0 +1,109 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlGetTD0, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x71, response1[1]); + cester_assert_uint_eq(0x28, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 0: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD1, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 1; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0, response1[1]); + cester_assert_uint_eq(2, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 40cdcc959..ea1e2424b 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -36,6 +36,7 @@ SOFTWARE. #include "exotic/cester.h" #include "cester-hw.c" +#include "cdlgettd.c" #include "cdlgettn.c" #include "cdlinit.c" #include "cdlseek.c" From 19595d7bb543ef3b75133c63ed85f77902a5dcb2 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 12:33:22 -0800 Subject: [PATCH 063/185] Adding more GetTD tests. --- src/mips/tests/cdrom/cdlgettd.c | 289 ++++++++++++++++++++++++++++++++ 1 file changed, 289 insertions(+) diff --git a/src/mips/tests/cdrom/cdlgettd.c b/src/mips/tests/cdrom/cdlgettd.c index 96c402a8f..1ec6ed5c4 100644 --- a/src/mips/tests/cdrom/cdlgettd.c +++ b/src/mips/tests/cdrom/cdlgettd.c @@ -107,3 +107,292 @@ CESTER_TEST(cdlGetTD1, test_instance, IMASK = imask; ) + + +CESTER_TEST(cdlGetTD2, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 2; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x70, response1[1]); + cester_assert_uint_eq(2, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) + + +CESTER_TEST(cdlGetTD3, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 3; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x70, response1[1]); + cester_assert_uint_eq(7, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD4, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 4; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x70, response1[1]); + cester_assert_uint_eq(0x14, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD5, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 5; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x70, response1[1]); + cester_assert_uint_eq(0x20, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD6, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 6; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x70, response1[1]); + cester_assert_uint_eq(0x24, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD12, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x12; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x70, response1[1]); + cester_assert_uint_eq(0x43, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD25, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x25; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x71, response1[1]); + cester_assert_uint_eq(0x25, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) From c3ac585ba65974b9731153373733ab2b83c972dd Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 13:49:42 -0800 Subject: [PATCH 064/185] Adding some more GetTD tests. --- src/mips/tests/cdrom/cdlgettd.c | 214 ++++++++++++++++++++++++++++++-- 1 file changed, 207 insertions(+), 7 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgettd.c b/src/mips/tests/cdrom/cdlgettd.c index 1ec6ed5c4..7ccbd7f16 100644 --- a/src/mips/tests/cdrom/cdlgettd.c +++ b/src/mips/tests/cdrom/cdlgettd.c @@ -145,7 +145,7 @@ CESTER_TEST(cdlGetTD2, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Basic getTD 2: ack in %ius\n", ackTime); IMASK = imask; ) @@ -187,7 +187,7 @@ CESTER_TEST(cdlGetTD3, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Basic getTD 3: ack in %ius\n", ackTime); IMASK = imask; ) @@ -228,7 +228,7 @@ CESTER_TEST(cdlGetTD4, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Basic getTD 4: ack in %ius\n", ackTime); IMASK = imask; ) @@ -269,7 +269,7 @@ CESTER_TEST(cdlGetTD5, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Basic getTD 5: ack in %ius\n", ackTime); IMASK = imask; ) @@ -310,7 +310,7 @@ CESTER_TEST(cdlGetTD6, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Basic getTD 6: ack in %ius\n", ackTime); IMASK = imask; ) @@ -351,7 +351,7 @@ CESTER_TEST(cdlGetTD12, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Basic getTD 12: ack in %ius\n", ackTime); IMASK = imask; ) @@ -392,7 +392,207 @@ CESTER_TEST(cdlGetTD25, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Basic getTD 25: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD99, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x99; + CDROM_REG1 = CDL_GETTD; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x10, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Basic getTD 99: errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTDaa, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0xaa; + CDROM_REG1 = CDL_GETTD; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x10, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Basic getTD aa: errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTD1a, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x1a; + CDROM_REG1 = CDL_GETTD; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x10, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Basic getTD 1a: errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTDNoArgs, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETTD; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("No args getTD: errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlGetTDTooManyArgs, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_GETTD; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Too many args getTD: errored in %ius\n", errorTime); IMASK = imask; ) From 2e619d3bffbbe15c1a4699162d8a9a7e1816fe4f Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 16:47:44 -0800 Subject: [PATCH 065/185] Couple more getTD tests. --- src/mips/tests/cdrom/cdlgettd.c | 80 +++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/mips/tests/cdrom/cdlgettd.c b/src/mips/tests/cdrom/cdlgettd.c index 7ccbd7f16..9d9200fa8 100644 --- a/src/mips/tests/cdrom/cdlgettd.c +++ b/src/mips/tests/cdrom/cdlgettd.c @@ -397,6 +397,46 @@ CESTER_TEST(cdlGetTD25, test_instance, IMASK = imask; ) +CESTER_TEST(cdlGetTD26, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x26; + CDROM_REG1 = CDL_GETTD; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x10, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Basic getTD 26: errored in %ius\n", errorTime); + + IMASK = imask; +) + CESTER_TEST(cdlGetTD99, test_instance, uint32_t imask = IMASK; @@ -477,6 +517,46 @@ CESTER_TEST(cdlGetTDaa, test_instance, IMASK = imask; ) +CESTER_TEST(cdlGetTD0a, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x0a; + CDROM_REG1 = CDL_GETTD; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x10, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 1500); + ramsyscall_printf("Basic getTD 0a: errored in %ius\n", errorTime); + + IMASK = imask; +) + CESTER_TEST(cdlGetTD1a, test_instance, uint32_t imask = IMASK; From c60a08d4397cb31ea9db34beb479c8df49e2e30c Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 24 Dec 2022 16:48:02 -0800 Subject: [PATCH 066/185] Fixing implicit indices in cueparser. --- third_party/cueparser/cueparser.c | 20 ++++++++++---------- third_party/cueparser/cueparser.h | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/third_party/cueparser/cueparser.c b/third_party/cueparser/cueparser.c index 89acfd728..d96cc972a 100644 --- a/third_party/cueparser/cueparser.c +++ b/third_party/cueparser/cueparser.c @@ -132,6 +132,7 @@ void CueParser_construct(struct CueParser* parser, struct CueDisc* disc) { parser->currentFile = NULL; parser->currentTrack = 0; parser->currentSectorNumber = 0; + parser->cutting = 0; parser->isTrackANewFile = 0; disc->catalog[0] = 0; disc->isrc[0] = 0; @@ -465,15 +466,14 @@ static void parse(struct CueParser* parser, struct CueFile* file, struct CueSche } struct CueTrack* track = &parser->disc->tracks[parser->currentTrack]; track->indices[track->indexCount] = parser->currentSectorNumber + sectorNumber; - if (parser->implicitIndex) { - if (parser->currentTrack == 1) { - track->indices[0] = 0; - } else { - track->indices[0] = track->indices[1]; - track->indices[1] += parser->currentPregap; - track->fileOffset += parser->currentPregap; - parser->currentSectorNumber += parser->currentPregap; - } + if (track->indexCount == 0) { + parser->cutting = sectorNumber; + } else if (parser->implicitIndex) { + track->indices[0] = track->indices[1]; + track->indices[1] += parser->currentPregap; + track->fileOffset += parser->currentPregap + sectorNumber; + parser->cutting = sectorNumber; + parser->currentSectorNumber += parser->currentPregap; parser->implicitIndex = 0; } parser->state = CUE_PARSER_START; @@ -584,7 +584,7 @@ static void parse(struct CueParser* parser, struct CueFile* file, struct CueSche track->serialCopyManagementSystem = 0; parser->currentPregap = 0; if (parser->isTrackANewFile) { - parser->currentSectorNumber += (parser->previousFileSize + 2351) / 2352; + parser->currentSectorNumber += (parser->previousFileSize + 2351) / 2352 - parser->cutting; parser->isTrackANewFile = 0; track->fileOffset = parser->currentSectorNumber; } else { diff --git a/third_party/cueparser/cueparser.h b/third_party/cueparser/cueparser.h index 85ed9deef..8bf28121e 100644 --- a/third_party/cueparser/cueparser.h +++ b/third_party/cueparser/cueparser.h @@ -85,6 +85,7 @@ struct CueParser { uint64_t currentFileSize; unsigned currentTrack; uint32_t currentSectorNumber; + uint32_t cutting; int implicitIndex; int isTrackANewFile; uint32_t currentPregap; From 7e6d2eddff29cf6e8429623303737101a345aa03 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 25 Dec 2022 09:15:19 -0800 Subject: [PATCH 067/185] More fixes to the cue parser. --- src/cdrom/cdriso-cue.cc | 2 +- third_party/cueparser/cueparser.c | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/cdrom/cdriso-cue.cc b/src/cdrom/cdriso-cue.cc index e7a8842f2..543f66850 100644 --- a/src/cdrom/cdriso-cue.cc +++ b/src/cdrom/cdriso-cue.cc @@ -169,7 +169,7 @@ bool PCSX::CDRIso::parsecue(const char *isofileString) { m_ti[i].handle.setFile(new SubFile(fi, (track->indices[1] - track->fileOffset) * 2352, track->size * 2352)); m_ti[i].type = track->trackType == TRACK_TYPE_AUDIO ? TrackType::CDDA : TrackType::DATA; m_ti[i].cddatype = track->compressed ? trackinfo::CCDDA : trackinfo::BIN; - m_ti[i].start = IEC60908b::MSF(track->indices[1]); + m_ti[i].start = IEC60908b::MSF(track->indices[1] + 150); m_ti[i].pregap = IEC60908b::MSF(track->indices[1] - track->indices[0]); m_ti[i].length = IEC60908b::MSF(track->size); } diff --git a/third_party/cueparser/cueparser.c b/third_party/cueparser/cueparser.c index d96cc972a..621081c05 100644 --- a/third_party/cueparser/cueparser.c +++ b/third_party/cueparser/cueparser.c @@ -465,16 +465,19 @@ static void parse(struct CueParser* parser, struct CueFile* file, struct CueSche return; } struct CueTrack* track = &parser->disc->tracks[parser->currentTrack]; - track->indices[track->indexCount] = parser->currentSectorNumber + sectorNumber; - if (track->indexCount == 0) { + if (parser->implicitIndex || (track->indexCount == 0)) { parser->cutting = sectorNumber; - } else if (parser->implicitIndex) { + parser->currentFileSize -= sectorNumber * 2352; + } + track->indices[track->indexCount] = parser->currentSectorNumber + sectorNumber - parser->cutting; + if (parser->implicitIndex) { track->indices[0] = track->indices[1]; track->indices[1] += parser->currentPregap; track->fileOffset += parser->currentPregap + sectorNumber; - parser->cutting = sectorNumber; parser->currentSectorNumber += parser->currentPregap; parser->implicitIndex = 0; + } else if (track->indexCount == 0) { + track->fileOffset += sectorNumber; } parser->state = CUE_PARSER_START; } break; @@ -584,7 +587,7 @@ static void parse(struct CueParser* parser, struct CueFile* file, struct CueSche track->serialCopyManagementSystem = 0; parser->currentPregap = 0; if (parser->isTrackANewFile) { - parser->currentSectorNumber += (parser->previousFileSize + 2351) / 2352 - parser->cutting; + parser->currentSectorNumber += (parser->previousFileSize + 2351) / 2352; parser->isTrackANewFile = 0; track->fileOffset = parser->currentSectorNumber; } else { From 5a290629b6bfef1b124fd20e219d86fb73b8bacb Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 25 Dec 2022 09:15:32 -0800 Subject: [PATCH 068/185] Implementing GetTD and passing tests. --- src/core/cdrom.cc | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 166318450..b88616b4b 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -486,6 +486,36 @@ class CDRomImpl final : public PCSX::CDRom { } } + // Command 20. + void cdlGetTD() { + switch (m_state) { + case 0: + m_state = 1; + schedule(750us); + break; + case 1: { + // TODO: probably should error out if no disc or + // lid open? + auto track = PCSX::IEC60908b::btoi(m_paramFIFO[0]); + if (!isValidBCD(m_paramFIFO[0]) || (track > m_iso->getTN())) { + setResponse(getStatus() | 1); + appendResponse(0x10); + m_cause = Cause::Error; + } else { + setResponse(getStatus()); + auto td = m_iso->getTD(track); + appendResponse(PCSX::IEC60908b::itob(td.m)); + appendResponse(PCSX::IEC60908b::itob(td.s)); + m_cause = Cause::Acknowledge; + } + m_paramFIFOSize = 0; + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + void cdlUnk() { switch (m_state) { case 0: @@ -527,7 +557,7 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlGetTN, // 16 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 + &CDRomImpl::cdlGetTD, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 28 #endif From 4e3193980bc58940f6f088327baaaea75fe7c31f Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 25 Dec 2022 21:11:54 -0800 Subject: [PATCH 069/185] Splitting cdlSeek, and adding cdlGetLoc tests. --- src/mips/tests/cdrom/cdlgetlocl.c | 58 +++++++ src/mips/tests/cdrom/cdlgetlocp.c | 87 +++++++++++ src/mips/tests/cdrom/cdlseekl.c | 147 ++++++++++++++++++ .../tests/cdrom/{cdlseek.c => cdlseekp.c} | 68 ++++---- src/mips/tests/cdrom/cdrom.c | 5 +- src/mips/tests/cdrom/cester-hw.c | 52 +++++++ 6 files changed, 379 insertions(+), 38 deletions(-) create mode 100644 src/mips/tests/cdrom/cdlgetlocl.c create mode 100644 src/mips/tests/cdrom/cdlgetlocp.c create mode 100644 src/mips/tests/cdrom/cdlseekl.c rename src/mips/tests/cdrom/{cdlseek.c => cdlseekp.c} (70%) diff --git a/src/mips/tests/cdrom/cdlgetlocl.c b/src/mips/tests/cdrom/cdlgetlocl.c new file mode 100644 index 000000000..98e1e01dc --- /dev/null +++ b/src/mips/tests/cdrom/cdlgetlocl.c @@ -0,0 +1,58 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlGetLocL, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCL; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Nothing of value is actually being read right after initialization, + // so there's no proper data in this response. + cester_assert_uint_eq(8, responseSize); + // Typical value seems to be around 1ms, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 6500); + ramsyscall_printf("Basic getlocL, complete in %ius\n", completeTime); +) diff --git a/src/mips/tests/cdrom/cdlgetlocp.c b/src/mips/tests/cdrom/cdlgetlocp.c new file mode 100644 index 000000000..ac0bb22fa --- /dev/null +++ b/src/mips/tests/cdrom/cdlgetlocp.c @@ -0,0 +1,87 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlGetLocP, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + struct LocPResult response; + uint8_t responseSize = readResponse((uint8_t*)&response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Right after reset, the drive will over close to 00:02:00, so + // the GetLocP will return values around that. Track will always + // be 01, and the oscillation will be of roughly 4 frames. Index + // will be 00 or 01 depending if the head is over the pregap, + // before or equal to absolute 00:01:74. The absolute time will + // be around 00:02:00, and the relative time will be around + // 00:00:00. The pregap relative time counts down to 0, so + // for an absolute time of 00:01:74, the relative time will be + // 00:00:01. For an absolute time of 00:01:73, the relative time + // will be 00:00:02, and so on. + int inPregap = response.index == 0; + uint32_t relative = MSF2LBA(btoi(response.m), btoi(response.s), btoi(response.f)); + uint32_t absolute = MSF2LBA(btoi(response.am), btoi(response.as), btoi(response.af)); + uint32_t onefifty = absolute; + if (inPregap) { + onefifty = absolute + relative; + } else { + onefifty = absolute - relative; + } + cester_assert_uint_eq(1, response.track); + cester_assert_uint_ge(onefifty, 150); + cester_assert_uint_ge(response.index, 0); + cester_assert_uint_le(response.index, 1); + cester_assert_uint_ge(absolute, 145); + cester_assert_uint_lt(absolute, 155); + cester_assert_uint_lt(relative, 5); + cester_assert_uint_eq(8, responseSize); + // Typical value seems to be around 1ms, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 6500); + ramsyscall_printf("Basic getlocP, complete in %ius\n", completeTime); + ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", + response.track, response.index, + response.m, response.s, response.f, relative, + response.am, response.as, response.af, absolute + ); +) diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c new file mode 100644 index 000000000..9b5bbf922 --- /dev/null +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -0,0 +1,147 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_SKIP_TEST(cdlSeekL, test_instance, +for (unsigned i = 0; i < 20; i++) { + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0, 2, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKL; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 2000); + // Typical value seems to be around 145ms. Of course, this is + // with a proper laser assy. + cester_assert_uint_ge(completeTime, 135000); + cester_assert_uint_lt(completeTime, 155000); + ramsyscall_printf("Basic seekL to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +} +) + +CESTER_TEST(cdlSeekLwithArgs, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0, 2, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SEEKL; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 2000); + ramsyscall_printf("Basic seekL with args, errored in %ius\n", errorTime); + + IMASK = imask; +) diff --git a/src/mips/tests/cdrom/cdlseek.c b/src/mips/tests/cdrom/cdlseekp.c similarity index 70% rename from src/mips/tests/cdrom/cdlseek.c rename to src/mips/tests/cdrom/cdlseekp.c index d4f60562f..08ad6961e 100644 --- a/src/mips/tests/cdrom/cdlseek.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -27,6 +27,7 @@ SOFTWARE. // clang-format off CESTER_SKIP_TEST(cdlSeekP, test_instance, +for (unsigned i = 0; i < 20; i++) { uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -37,11 +38,15 @@ CESTER_SKIP_TEST(cdlSeekP, test_instance, return; } - int setlocDone = setLoc(0, 2, 0); + int setLocDone = setLoc(0, 2, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } initializeTime(); - // wait 10ms for things to settle - while (updateTime() < 10000); + // wait 50ms for things to settle + while (updateTime() < 50000); initializeTime(); CDROM_REG0 = 0; @@ -77,9 +82,8 @@ CESTER_SKIP_TEST(cdlSeekP, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); - // Typical value seems to be around 750us. cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 1500); + cester_assert_uint_lt(ackTime, 2000); // Typical value seems to be around 105ms. Of course, this is // with a proper laser assy. cester_assert_uint_ge(completeTime, 100000); @@ -87,9 +91,10 @@ CESTER_SKIP_TEST(cdlSeekP, test_instance, ramsyscall_printf("Basic seekP to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); IMASK = imask; +} ) -CESTER_SKIP_TEST(cdlSeekL, test_instance, +CESTER_TEST(cdlSeekPwithArgs, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -100,17 +105,25 @@ CESTER_SKIP_TEST(cdlSeekL, test_instance, return; } - int setlocDone = setLoc(0, 2, 0); + int setLocDone = setLoc(0, 2, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } initializeTime(); - // wait 10ms for things to settle - while (updateTime() < 10000); + // wait 50ms for things to settle + while (updateTime() < 50000); initializeTime(); CDROM_REG0 = 0; - CDROM_REG1 = CDL_SEEKL; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_SEEKP; - uint32_t ackTime = waitCDRomIRQ(); + uint32_t errorTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response1[16]; @@ -119,35 +132,16 @@ CESTER_SKIP_TEST(cdlSeekL, test_instance, CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; - uint32_t completeTime = waitCDRomIRQ() - ackTime; - uint8_t cause2 = ackCDRomCause(); - uint8_t ctrl3 = CDROM_REG0 & ~3; - uint8_t response2[16]; - uint8_t responseSize2 = readResponse(response2); - uint8_t ctrl4 = CDROM_REG0 & ~3; - CDROM_REG0 = 1; - uint8_t cause2b = CDROM_REG3_UC; - - cester_assert_uint_eq(3, cause1); - cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(5, cause1); cester_assert_uint_eq(0xe0, cause1b); - cester_assert_uint_eq(0xe0, cause2b); - cester_assert_uint_eq(2, response1[0]); - cester_assert_uint_eq(1, responseSize1); - cester_assert_uint_eq(2, response2[0]); - cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); - cester_assert_uint_eq(0x38, ctrl3); - cester_assert_uint_eq(0x18, ctrl4); - // Typical value seems to be around 750us. - cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); - // Typical value seems to be around 145ms. Of course, this is - // with a proper laser assy. - cester_assert_uint_ge(completeTime, 140000); - cester_assert_uint_lt(completeTime, 150000); - ramsyscall_printf("Basic seekL to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 2000); + ramsyscall_printf("Basic seekP with args, errored in %ius\n", errorTime); IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index ea1e2424b..0f176950c 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -36,9 +36,12 @@ SOFTWARE. #include "exotic/cester.h" #include "cester-hw.c" +#include "cdlgetlocl.c" +#include "cdlgetlocp.c" #include "cdlgettd.c" #include "cdlgettn.c" #include "cdlinit.c" -#include "cdlseek.c" +#include "cdlseekl.c" +#include "cdlseekp.c" #include "cdlsetloc.c" #include "invalid.c" diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index f875fc6fc..fab02f25d 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -40,6 +40,27 @@ CESTER_BODY( static uint32_t s_currentTime = 0; static const unsigned US_PER_HBLANK = 64; + struct LocPResult { + uint8_t track, index, m, s, f, am, as, af; + uint8_t padding[8]; + }; + + static uint8_t btoi(uint8_t b) { + return (b >> 4) * 10 + (b & 0xf); + } + + static uint8_t itob(uint8_t i) { + return (i / 10) * 16 + (i % 10); + } + + static int isValidBCD(uint8_t b) { + return (b & 0xf) < 10 && (b >> 4) < 10; + } + + static uint32_t MSF2LBA(uint8_t m, uint8_t s, uint8_t f) { + return (m * 60 + s) * 75 + f; + } + static uint8_t readResponse(uint8_t response[16]) { uint8_t responseSize = 0; while ((CDROM_REG0 & 0x20) && (responseSize < 16)) { @@ -141,6 +162,37 @@ CESTER_BODY( waitCDRomIRQ(); cause = ackCDRomCause(); CDROM_REG1; + if (cause != 3) return 0; + + IMASK = imask; + return 1; + } + + static int seekTo(uint8_t minute, uint8_t second, uint8_t frame) { + uint32_t imask = IMASK; + uint8_t cause; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = minute; + CDROM_REG2 = second; + CDROM_REG2 = frame; + CDROM_REG1 = CDL_SETLOC; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) return 0; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) return 0; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; if (cause != 2) return 0; IMASK = imask; From db0ea115aef3a2c755524652ae40f529d0412554 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 25 Dec 2022 23:09:49 -0800 Subject: [PATCH 070/185] Making test pass, and removed some logging. --- src/cdrom/cdriso.cc | 31 ++++++++++++++++++++ src/cdrom/cdriso.h | 14 +++++---- src/cdrom/iec-60908b.h | 43 ++++++++++++++++++++++++++++ src/core/cdrom.cc | 64 +++++++++++++++++++++++++++++++++--------- src/core/cdrom.h | 1 + 5 files changed, 134 insertions(+), 19 deletions(-) diff --git a/src/cdrom/cdriso.cc b/src/cdrom/cdriso.cc index 63dbcecf7..85825ad32 100644 --- a/src/cdrom/cdriso.cc +++ b/src/cdrom/cdriso.cc @@ -427,6 +427,37 @@ PCSX::IEC60908b::MSF PCSX::CDRIso::getPregap(uint8_t track) { return IEC60908b::MSF(0, 2, 0); } +bool PCSX::CDRIso::getLocP(const PCSX::IEC60908b::MSF msf, uint8_t locP[8]) { + // TODO: actually check subchannels from iso. + auto length = getTD(0) + IEC60908b::MSF{0, 2, 0}; + if (msf >= length) return false; + unsigned track; + for (track = m_numtracks; track != 1; track--) { + if (m_ti[track].start <= msf) break; + } + + bool inPregap = false; + IEC60908b::MSF nextPregapStart; + if (track != m_numtracks) { + if (msf >= (m_ti[track + 1].start - m_ti[track + 1].pregap)) { + track++; + inPregap = true; + } + } + locP[0] = IEC60908b::itob(track); + locP[1] = inPregap ? 0 : 1; + IEC60908b::MSF relative; + if (inPregap) { + m_ti[track].start - msf; + } else { + relative = msf - m_ti[track].start; + } + relative.toBCD(locP + 2); + msf.toBCD(locP + 5); + + return true; +} + // Decode 'raw' subchannel data from being packed bitwise. // Essentially is a bitwise matrix transposition. void PCSX::CDRIso::decodeRawSubData() { diff --git a/src/cdrom/cdriso.h b/src/cdrom/cdriso.h index 828cddb6a..1d69fa6bb 100644 --- a/src/cdrom/cdriso.h +++ b/src/cdrom/cdriso.h @@ -45,18 +45,21 @@ class CDRIso { enum class TrackType { CLOSED = 0, DATA = 1, CDDA = 2 }; TrackType getTrackType(unsigned track) { return m_ti[track].type; } const std::filesystem::path& getIsoPath() { return m_isoPath; } - uint8_t getTN() { return std::max(m_numtracks, 1); } + uint8_t getTN() { return std::max(m_numtracks, 1U); } IEC60908b::MSF getTD(uint8_t track); IEC60908b::MSF getLength(uint8_t track); IEC60908b::MSF getPregap(uint8_t track); + bool getLocP(const IEC60908b::MSF msf, uint8_t locP[8]); + + bool failed(); + + /* Probably have to change those */ bool readTrack(const IEC60908b::MSF time); unsigned readSectors(uint32_t lba, void* buffer, unsigned count); uint8_t* getBuffer(); const IEC60908b::Sub* getBufferSub(); bool readCDDA(const IEC60908b::MSF msf, unsigned char* buffer); - bool failed(); - unsigned m_cdrIsoMultidiskCount; unsigned m_cdrIsoMultidiskSelect; @@ -127,7 +130,6 @@ class CDRIso { ECMFILELUT* m_ecm_savetable = nullptr; static inline const size_t ECM_SECTOR_SIZE[4] = {1, 2352, 2336, 2336}; - static inline const uint8_t ZEROADDRESS[4] = {0, 0, 0, 0}; struct trackinfo { TrackType type = TrackType::CLOSED; @@ -136,12 +138,12 @@ class CDRIso { IEC60908b::MSF length; IO handle = nullptr; // for multi-track images CDDA enum cddatype_t { NONE = 0, BIN = 1, CCDDA = 2 } cddatype = NONE; // BIN, WAV, MP3, APE - uint32_t start_offset = 0; // byte offset from start of above file + uint32_t start_offset = 0; // byte offset from start of above file }; static constexpr unsigned MAXTRACKS = 100; /* How many tracks can a CD hold? */ - int m_numtracks = 0; + unsigned m_numtracks = 0; struct trackinfo m_ti[MAXTRACKS]; // redump.org SBI files diff --git a/src/cdrom/iec-60908b.h b/src/cdrom/iec-60908b.h index 941750b6a..a29d764ce 100644 --- a/src/cdrom/iec-60908b.h +++ b/src/cdrom/iec-60908b.h @@ -112,6 +112,49 @@ struct MSF { ++(*this); return tmp; } + MSF &operator--() { + if (f == 0) { + f = 74; + if (s == 0) { + s = 59; + if (m == 0) { + m = 99; + } else { + m--; + } + } else { + s--; + } + } else { + f--; + } + return *this; + } + MSF operator--(int) { + MSF tmp = *this; + --(*this); + return tmp; + } + MSF operator+(const MSF &other) const { + MSF tmp = *this; + tmp += other; + return tmp; + } + MSF operator-(const MSF &other) const { + MSF tmp = *this; + tmp -= other; + return tmp; + } + MSF &operator+=(const MSF &other) { + uint32_t lba = toLBA() + other.toLBA(); + *this = MSF(lba); + return *this; + } + MSF &operator-=(const MSF &other) { + uint32_t lba = toLBA() - other.toLBA(); + *this = MSF(lba); + return *this; + } constexpr uint32_t toLBA() const { return (m * 60 + s) * 75 + f; } constexpr void toBCD(uint8_t *dst) const { dst[0] = itob(m); diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index b88616b4b..f69f1f959 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -123,10 +123,7 @@ class CDRomImpl final : public PCSX::CDRom { void dmaInterrupt() override {} - void schedule(uint32_t cycles) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: scheduling callback in %d cycles\n", cycles); - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDR, cycles); - } + void schedule(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDR, cycles); } void schedule(std::chrono::nanoseconds delay) { schedule(PCSX::psxRegisters::durationToCycles(delay)); } void scheduleRead(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDREAD, cycles); } @@ -437,7 +434,10 @@ class CDRomImpl final : public PCSX::CDRom { m_state = 1; m_motorOn = true; m_currentPosition.reset(); + m_currentPosition.s = 2; m_seekPosition.reset(); + m_seekPosition.s = 2; + memset(m_lastLocP, 0, sizeof(m_lastLocP)); schedule(2ms); break; case 1: @@ -464,6 +464,45 @@ class CDRomImpl final : public PCSX::CDRom { } } + // Command 16. + void cdlGetLocL() { + switch (m_state) { + case 0: + m_state = 1; + schedule(750us); + break; + case 1: { + // TODO: probably should error out if no disc or + // lid open? + setResponse("TODOTODO"sv); + m_cause = Cause::Acknowledge; + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + + // Command 17. + void cdlGetLocP() { + switch (m_state) { + case 0: + m_state = 1; + schedule(750us); + break; + case 1: { + // TODO: probably should error out if no disc or + // lid open? + m_iso->getLocP(m_currentPosition, m_lastLocP); + setResponse(std::string_view((char *)m_lastLocP, sizeof(m_lastLocP))); + m_cause = Cause::Acknowledge; + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + // Command 19. void cdlGetTN() { switch (m_state) { @@ -478,7 +517,6 @@ class CDRomImpl final : public PCSX::CDRom { appendResponse(1); appendResponse(PCSX::IEC60908b::itob(m_iso->getTN())); m_cause = Cause::Acknowledge; - m_paramFIFOSize = 0; m_state = 0; m_command = 0; triggerIRQ(); @@ -552,14 +590,14 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 &CDRomImpl::cdlReset, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 #else - &CDRomImpl::cdlUnk, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlGetTN, // 16 - &CDRomImpl::cdlGetTD, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 28 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 + &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, &CDRomImpl::cdlUnk, &CDRomImpl::cdlGetTN, // 16 + &CDRomImpl::cdlGetTD, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 28 #endif }; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 6c7a0a466..e6808a85e 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -148,6 +148,7 @@ class CDRom { MSF m_currentPosition; MSF m_seekPosition; + uint8_t m_lastLocP[8] = {0}; private: friend class Widgets::IsoBrowser; From dc1188b169acf72fd0560b2d05cf3b34c86dc406 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 10:01:32 -0800 Subject: [PATCH 071/185] Adjusting timings a bit and messages, and adding some seek tests. --- src/mips/tests/cdrom/cdlgetlocl.c | 2 +- src/mips/tests/cdrom/cdlgettd.c | 14 +- src/mips/tests/cdrom/cdlgettn.c | 4 +- src/mips/tests/cdrom/cdlinit.c | 2 +- src/mips/tests/cdrom/cdlseekl.c | 233 ++++++++++++++++++++++++++++-- src/mips/tests/cdrom/cdlseekp.c | 228 ++++++++++++++++++++++++++++- src/mips/tests/cdrom/invalid.c | 2 +- 7 files changed, 456 insertions(+), 29 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgetlocl.c b/src/mips/tests/cdrom/cdlgetlocl.c index 98e1e01dc..f289324dd 100644 --- a/src/mips/tests/cdrom/cdlgetlocl.c +++ b/src/mips/tests/cdrom/cdlgetlocl.c @@ -53,6 +53,6 @@ CESTER_TEST(cdlGetLocL, test_instances, // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 6500); + cester_assert_uint_lt(completeTime, 7000); ramsyscall_printf("Basic getlocL, complete in %ius\n", completeTime); ) diff --git a/src/mips/tests/cdrom/cdlgettd.c b/src/mips/tests/cdrom/cdlgettd.c index 9d9200fa8..97756f492 100644 --- a/src/mips/tests/cdrom/cdlgettd.c +++ b/src/mips/tests/cdrom/cdlgettd.c @@ -431,7 +431,7 @@ CESTER_TEST(cdlGetTD26, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 26: errored in %ius\n", errorTime); IMASK = imask; @@ -471,7 +471,7 @@ CESTER_TEST(cdlGetTD99, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 99: errored in %ius\n", errorTime); IMASK = imask; @@ -511,7 +511,7 @@ CESTER_TEST(cdlGetTDaa, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD aa: errored in %ius\n", errorTime); IMASK = imask; @@ -551,7 +551,7 @@ CESTER_TEST(cdlGetTD0a, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 0a: errored in %ius\n", errorTime); IMASK = imask; @@ -591,7 +591,7 @@ CESTER_TEST(cdlGetTD1a, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 1a: errored in %ius\n", errorTime); IMASK = imask; @@ -630,7 +630,7 @@ CESTER_TEST(cdlGetTDNoArgs, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("No args getTD: errored in %ius\n", errorTime); IMASK = imask; @@ -671,7 +671,7 @@ CESTER_TEST(cdlGetTDTooManyArgs, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Too many args getTD: errored in %ius\n", errorTime); IMASK = imask; diff --git a/src/mips/tests/cdrom/cdlgettn.c b/src/mips/tests/cdrom/cdlgettn.c index 84c050d4d..80ea04a2d 100644 --- a/src/mips/tests/cdrom/cdlgettn.c +++ b/src/mips/tests/cdrom/cdlgettn.c @@ -105,8 +105,8 @@ CESTER_TEST(cdlGetTNWithArgs, test_instance, cester_assert_uint_eq(0x18, ctrl2); // Typical value seems to be around 750us. cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); - ramsyscall_printf("Basic getTN: errored in %ius\n", errorTime); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("Too many args getTN: errored in %ius\n", errorTime); IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlinit.c b/src/mips/tests/cdrom/cdlinit.c index a3610b465..553a17b32 100644 --- a/src/mips/tests/cdrom/cdlinit.c +++ b/src/mips/tests/cdrom/cdlinit.c @@ -198,7 +198,7 @@ CESTER_TEST(cdlInitWithArgs, test_instance, cester_assert_uint_lt(errorTime, 2000); // Typical value seems to be around 1.5ms. cester_assert_uint_ge(ackTime, 1000); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 3500); ramsyscall_printf("Initialization with args: CD-Rom controller errored, error in %ius\n", errorTime); ramsyscall_printf("Initialization with args: requested status, ack in %ius\n", ackTime); diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c index 9b5bbf922..6094e6b99 100644 --- a/src/mips/tests/cdrom/cdlseekl.c +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -26,8 +26,7 @@ SOFTWARE. // clang-format off -CESTER_SKIP_TEST(cdlSeekL, test_instance, -for (unsigned i = 0; i < 20; i++) { +CESTER_TEST(cdlSeekL, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -83,15 +82,13 @@ for (unsigned i = 0; i < 20; i++) { cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); - // Typical value seems to be around 145ms. Of course, this is - // with a proper laser assy. - cester_assert_uint_ge(completeTime, 135000); - cester_assert_uint_lt(completeTime, 155000); + cester_assert_uint_lt(ackTime, 7000); + // Timings here won't really be relevant, as the CDRom's head will be hovering + // already around the right place, so it's mostly a no-op to seek there, but + // can vary a lot between 2ms and 500ms as the head is moving and re-aligning. ramsyscall_printf("Basic seekL to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); IMASK = imask; -} ) CESTER_TEST(cdlSeekLwithArgs, test_instance, @@ -141,7 +138,225 @@ CESTER_TEST(cdlSeekLwithArgs, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 2000); - ramsyscall_printf("Basic seekL with args, errored in %ius\n", errorTime); + ramsyscall_printf("Too many args seekL, errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSeekL2to4, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0, 4, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKL; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 2000); + // It'd be difficult to put an interval check here, as the seek time will vary + // a lot depending on the status of the drive, but it should probably be + // at least 120ms, and more likely 170ms. + ramsyscall_printf("Basic seekL from 00:02:00 to 00:04:00: ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSeekL2to71, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x71, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKL; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t errorTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(4, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 2000); + // The seekL won't be successful when targeting a sector past the end of the + // data track, but it should still take a while to complete, because it'll + // keep retrying reading data where there's none. Roughly 4s. + cester_assert_uint_ge(errorTime, 4000000); + ramsyscall_printf("Basic seekL from 00:02:00 to 71:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSeekL2to99, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x99, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKL; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t errorTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(16, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 2000); + // The seekL won't be successful when targeting a sector past the end of the + // disc. The failure can be faster than the previous test, because it won't + // retry reading where there's clearly no information whatsoever. Will sometimes + // fail in roughly 650ms, which is the seek time plus some minor retry. + cester_assert_uint_ge(errorTime, 600000); + ramsyscall_printf("Basic seekL from 00:02:00 to 99:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 08ad6961e..4c8c15a12 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -26,8 +26,7 @@ SOFTWARE. // clang-format off -CESTER_SKIP_TEST(cdlSeekP, test_instance, -for (unsigned i = 0; i < 20; i++) { +CESTER_TEST(cdlSeekP, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -84,14 +83,12 @@ for (unsigned i = 0; i < 20; i++) { cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 2000); - // Typical value seems to be around 105ms. Of course, this is - // with a proper laser assy. - cester_assert_uint_ge(completeTime, 100000); - cester_assert_uint_lt(completeTime, 110000); + // Timings here won't really be relevant, as the CDRom's head will be hovering + // already around the right place, so it's mostly a no-op to seek there, but + // can vary a lot between 2ms and 500ms as the head is moving and re-aligning. ramsyscall_printf("Basic seekP to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); IMASK = imask; -} ) CESTER_TEST(cdlSeekPwithArgs, test_instance, @@ -141,7 +138,222 @@ CESTER_TEST(cdlSeekPwithArgs, test_instance, cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 2000); - ramsyscall_printf("Basic seekP with args, errored in %ius\n", errorTime); + ramsyscall_printf("Too many args seekP, errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSeekP2to4, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0, 4, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 2000); + // It'd be difficult to put an interval check here, as the seek time will vary + // a lot depending on the status of the drive, but it should probably be + // at least 100ms, and more likely 150ms. + ramsyscall_printf("Basic seekP from 00:02:00 to 00:04:00: ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSeekP2to71, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x71, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 2000); + // This is a pretty long distance seek, which will take at least a full second. + cester_assert_uint_ge(completeTime, 1000000); + ramsyscall_printf("Basic seekP from 00:02:00 to 71:00:00: ack in %ius, complete in %ius\n", ackTime, completeTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSeekP2to99, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x99, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t errorTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(16, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 2000); + // The seekP won't be successful when targeting a sector past the end of the + // disc. The failure can be faster than the previous test, because it won't + // retry reading where there's clearly no information whatsoever. Will sometimes + // fail in roughly 650ms, which is the seek time plus some minor retry. + cester_assert_uint_ge(errorTime, 600000); + ramsyscall_printf("Basic seekP from 00:02:00 to 99:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); IMASK = imask; ) diff --git a/src/mips/tests/cdrom/invalid.c b/src/mips/tests/cdrom/invalid.c index 6990fa854..47df576bc 100644 --- a/src/mips/tests/cdrom/invalid.c +++ b/src/mips/tests/cdrom/invalid.c @@ -60,7 +60,7 @@ CESTER_TEST(invalid0, test_instance, cester_assert_uint_eq(0x18, ctrl2); // Typical value seems to be around 750us. cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 1500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Invalid command 0: errored in %ius\n", errorTime); IMASK = imask; From 623b46cb1b515357ddc0490263d897cd03c156ca Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 10:09:10 -0800 Subject: [PATCH 072/185] Adding blurb about missing tests. --- src/mips/tests/cdrom/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index 088d266ce..a2653501a 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -18,6 +18,6 @@ The tests are currently being run on a 9001 machine for its real hardware routin The code is commented to explain what is being tested, and why. The tests are also written to be as self-contained as possible, so that they can be easily copied and modified to test other things. -All in all, these tests are overdoing it in terms of state and feature tests, and over aggressive. PS1 games most definitely do not need this level of accuracy, but this controller is so finicky that it is better to be safe than sorry. An emulator able to pass these tests ought to be able to run anything, as long as the main CPU timings are somewhat accurate. +All in all, these tests are overdoing it in terms of state and feature tests, and over aggressive. PS1 games most definitely do not need this level of accuracy, but this controller is so finicky that it is better to be safe than sorry. An emulator able to pass these tests ought to be able to run anything, as long as the main CPU timings are somewhat accurate. If any of these tests fail, it is likely that the emulator is not emulating the controller properly. If games are still failing despite the tests passing, this would mean there's a behavior not covered by the tests, and they shall be updated accordingly. A word on timings: the timings are measured using the hblank timer, which is usually pretty easy to get right in terms of accuracy. However, many games will have busy wait loop when talking to the controller, or race conditions between sending commands. This means that if the CPU runs too slow or too quickly, bugs will surface. If the emulator is passing the timing tests, but games are failing, it is likely that the CPU emulation speed accuracy is at fault here, not the controller's. From 658646e3fa857f51afbbf973b33eafbc068d660b Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 13:08:56 -0800 Subject: [PATCH 073/185] Adding a few more files to gitignore. --- .gitignore | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7f431349d..8f7be9b40 100644 --- a/.gitignore +++ b/.gitignore @@ -69,7 +69,7 @@ fb.bat *.sstate9 # GPU dump files -*.dump +*.dump # IDA database files *.id0 @@ -98,3 +98,12 @@ DynarecOutput.map DynarecProfileData.txt DynarecDisassembly.txt sstate.proto + +# nops' configuration file +comport.txt + +# Cue sheets. +*.cue + +# Various editors' backup files +*.bak From 298709cb853e0d1d7de8b5067671f4f35ef82aea Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 14:45:42 -0800 Subject: [PATCH 074/185] Making seek tests pass. --- src/cdrom/cdriso.cc | 16 +++++++ src/cdrom/cdriso.h | 1 + src/core/cdrom.cc | 105 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 120 insertions(+), 2 deletions(-) diff --git a/src/cdrom/cdriso.cc b/src/cdrom/cdriso.cc index 85825ad32..d1912bf40 100644 --- a/src/cdrom/cdriso.cc +++ b/src/cdrom/cdriso.cc @@ -458,6 +458,22 @@ bool PCSX::CDRIso::getLocP(const PCSX::IEC60908b::MSF msf, uint8_t locP[8]) { return true; } +unsigned PCSX::CDRIso::getTrack(const PCSX::IEC60908b::MSF msf) { + auto length = getTD(0) + IEC60908b::MSF{0, 2, 0}; + if (msf >= length) return 0; + unsigned track; + for (track = m_numtracks; track != 1; track--) { + if (m_ti[track].start <= msf) break; + } + IEC60908b::MSF nextPregapStart; + if (track != m_numtracks) { + if (msf >= (m_ti[track + 1].start - m_ti[track + 1].pregap)) { + track++; + } + } + return track; +} + // Decode 'raw' subchannel data from being packed bitwise. // Essentially is a bitwise matrix transposition. void PCSX::CDRIso::decodeRawSubData() { diff --git a/src/cdrom/cdriso.h b/src/cdrom/cdriso.h index 1d69fa6bb..665431ae1 100644 --- a/src/cdrom/cdriso.h +++ b/src/cdrom/cdriso.h @@ -50,6 +50,7 @@ class CDRIso { IEC60908b::MSF getLength(uint8_t track); IEC60908b::MSF getPregap(uint8_t track); bool getLocP(const IEC60908b::MSF msf, uint8_t locP[8]); + unsigned getTrack(const IEC60908b::MSF msf); bool failed(); diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index f69f1f959..b90ffba58 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -378,6 +378,25 @@ class CDRomImpl final : public PCSX::CDRom { (this->*handler)(); } + enum class SeekType { DATA, CDDA }; + + std::chrono::nanoseconds computeSeekDelay(MSF from, MSF to, SeekType seekType) { + unsigned destTrack = m_iso->getTrack(to); + if (destTrack == 0) return 650ms; + if ((seekType == SeekType::DATA) && (m_iso->getTrackType(destTrack) == PCSX::CDRIso::TrackType::CDDA)) { + return 4s; + } + uint32_t distance = 0; + if (from > to) { + distance = (from - to).toLBA(); + } else { + distance = (to - from).toLBA(); + } + // TODO: ought to be a decent approximation for now, + // but may require some tuning later on. + return std::chrono::microseconds(distance * 3) + 150ms; + } + // Command 1. void cdlNop() { switch (m_state) { @@ -457,8 +476,8 @@ class CDRomImpl final : public PCSX::CDRom { case 3: m_cause = Cause::Complete; m_state = 0; - setResponse(getStatus()); m_command = 0; + setResponse(getStatus()); triggerIRQ(); break; } @@ -554,6 +573,88 @@ class CDRomImpl final : public PCSX::CDRom { } } + // Command 21. + void cdlSeekL() { + switch (m_state) { + case 0: + m_state = 1; + schedule(1ms); + break; + case 1: + m_cause = Cause::Acknowledge; + m_state = 2; + setResponse(getStatus()); + triggerIRQ(); + schedule(computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA)); + break; + case 2: + if (!m_gotAck) { + m_waitingAck = true; + m_state = 3; + break; + } + [[fallthrough]]; + case 3: { + // TODO: read sector and cache sector header for locL + m_currentPosition = m_seekPosition; + unsigned track = m_iso->getTrack(m_seekPosition); + if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(4); + } else if (track == 0) { + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(0x10); + } else { + m_cause = Cause::Complete; + setResponse(getStatus()); + } + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + + // Command 22. + void cdlSeekP() { + switch (m_state) { + case 0: + m_state = 1; + schedule(1ms); + break; + case 1: + m_cause = Cause::Acknowledge; + m_state = 2; + setResponse(getStatus()); + triggerIRQ(); + schedule(computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::CDDA)); + break; + case 2: + if (!m_gotAck) { + m_waitingAck = true; + m_state = 3; + break; + } + [[fallthrough]]; + case 3: { + m_currentPosition = m_seekPosition; + if (m_iso->getTrack(m_seekPosition) == 0) { + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(0x10); + } else { + m_cause = Cause::Complete; + setResponse(getStatus()); + } + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + void cdlUnk() { switch (m_state) { case 0: @@ -595,7 +696,7 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, &CDRomImpl::cdlUnk, &CDRomImpl::cdlGetTN, // 16 - &CDRomImpl::cdlGetTD, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 20 + &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, &CDRomImpl::cdlUnk, // 20 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 28 #endif From 67fd76cbc6bd9aa0cb2ee7a8840f4f0a867d6e0b Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 15:55:26 -0800 Subject: [PATCH 075/185] Adding some more getLoc tests. --- src/mips/tests/cdrom/cdlgetlocl.c | 44 ++++++++++- src/mips/tests/cdrom/cdlgetlocp.c | 120 ++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdlseekl.c | 6 +- src/mips/tests/cdrom/cdlseekp.c | 6 +- src/mips/tests/cdrom/cester-hw.c | 33 +++++++- 5 files changed, 201 insertions(+), 8 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgetlocl.c b/src/mips/tests/cdrom/cdlgetlocl.c index f289324dd..ce94b9f95 100644 --- a/src/mips/tests/cdrom/cdlgetlocl.c +++ b/src/mips/tests/cdrom/cdlgetlocl.c @@ -48,7 +48,10 @@ CESTER_TEST(cdlGetLocL, test_instances, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); // Nothing of value is actually being read right after initialization, - // so there's no proper data in this response. + // so there's no proper data in this response. There's somewhat of a + // bug in the controller, where doing a GetLocL right after a reset + // will actually work, whereas it shouldn't, as GetLocL is only supposed + // to work during a data transfer. cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. @@ -56,3 +59,42 @@ CESTER_TEST(cdlGetLocL, test_instances, cester_assert_uint_lt(completeTime, 7000); ramsyscall_printf("Basic getlocL, complete in %ius\n", completeTime); ) + +CESTER_TEST(cdlGetLocLafterSeekL, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + int seekDone = seekLTo(0x50, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCL; + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Since we've done a seekL, without a read, we will actually + // error out here, unlike the previous test. + cester_assert_uint_eq(2, responseSize); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(0x80, response[1]); + // Typical value seems to be around 750us, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("Basic getlocL after seekL, errored in %ius\n", errorTime); +) diff --git a/src/mips/tests/cdrom/cdlgetlocp.c b/src/mips/tests/cdrom/cdlgetlocp.c index ac0bb22fa..35e5437b5 100644 --- a/src/mips/tests/cdrom/cdlgetlocp.c +++ b/src/mips/tests/cdrom/cdlgetlocp.c @@ -85,3 +85,123 @@ CESTER_TEST(cdlGetLocP, test_instances, response.am, response.as, response.af, absolute ); ) + +CESTER_TEST(cdlGetLocPafterSeekP, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + int seekDone = seekTo(0x50, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + struct LocPResult response; + uint8_t responseSize = readResponse((uint8_t*)&response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // After a simple seekP, the head will hover around the seeked + // position, so the GetLocP will return values before that. Distance + // from the seeked position will be up to 50 frames around this location. + int inPregap = response.index == 0; + uint32_t relative = MSF2LBA(btoi(response.m), btoi(response.s), btoi(response.f)); + uint32_t absolute = MSF2LBA(btoi(response.am), btoi(response.as), btoi(response.af)); + uint32_t onefifty = absolute; + if (inPregap) { + onefifty = absolute + relative; + } else { + onefifty = absolute - relative; + } + cester_assert_uint_eq(1, response.track); + cester_assert_uint_ge(onefifty, 150); + cester_assert_uint_eq(inPregap, 0); + cester_assert_uint_eq(response.index, 1); + cester_assert_uint_ge(absolute, 224950); + cester_assert_uint_lt(absolute, 225000); + cester_assert_uint_ge(relative, 224800); + cester_assert_uint_lt(relative, 224850); + cester_assert_uint_eq(8, responseSize); + // Typical value seems to be around 1ms, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 7000); + ramsyscall_printf("Basic getlocP after seekP, complete in %ius\n", completeTime); + ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", + response.track, response.index, + response.m, response.s, response.f, relative, + response.am, response.as, response.af, absolute + ); +) + +CESTER_TEST(cdlGetLocPafterSeekL, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + int seekDone = seekLTo(0x50, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + struct LocPResult response; + uint8_t responseSize = readResponse((uint8_t*)&response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // After a simple seekP, the head will hover around the seeked + // position, so the GetLocP will return values before that. Distance + // from the seeked position will be up to 50 frames around this location. + int inPregap = response.index == 0; + uint32_t relative = MSF2LBA(btoi(response.m), btoi(response.s), btoi(response.f)); + uint32_t absolute = MSF2LBA(btoi(response.am), btoi(response.as), btoi(response.af)); + uint32_t onefifty = absolute; + if (inPregap) { + onefifty = absolute + relative; + } else { + onefifty = absolute - relative; + } + cester_assert_uint_eq(1, response.track); + cester_assert_uint_ge(onefifty, 150); + cester_assert_uint_eq(inPregap, 0); + cester_assert_uint_eq(response.index, 1); + cester_assert_uint_ge(absolute, 224950); + cester_assert_uint_lt(absolute, 225000); + cester_assert_uint_ge(relative, 224800); + cester_assert_uint_lt(relative, 224850); + cester_assert_uint_eq(8, responseSize); + // Typical value seems to be around 1ms, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 7000); + ramsyscall_printf("Basic getlocP after seekL, complete in %ius\n", completeTime); + ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", + response.track, response.index, + response.m, response.s, response.f, relative, + response.am, response.as, response.af, absolute + ); +) diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c index 6094e6b99..e7eb5c1ee 100644 --- a/src/mips/tests/cdrom/cdlseekl.c +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -154,7 +154,7 @@ CESTER_TEST(cdlSeekL2to4, test_instance, return; } - int seekDone = seekTo(0, 2, 0); + int seekDone = seekPTo(0, 2, 0); if (!seekDone) { cester_assert_true(seekDone); return; @@ -225,7 +225,7 @@ CESTER_TEST(cdlSeekL2to71, test_instance, return; } - int seekDone = seekTo(0, 2, 0); + int seekDone = seekPTo(0, 2, 0); if (!seekDone) { cester_assert_true(seekDone); return; @@ -298,7 +298,7 @@ CESTER_TEST(cdlSeekL2to99, test_instance, return; } - int seekDone = seekTo(0, 2, 0); + int seekDone = seekPTo(0, 2, 0); if (!seekDone) { cester_assert_true(seekDone); return; diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 4c8c15a12..27abb96d0 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -154,7 +154,7 @@ CESTER_TEST(cdlSeekP2to4, test_instance, return; } - int seekDone = seekTo(0, 2, 0); + int seekDone = seekPTo(0, 2, 0); if (!seekDone) { cester_assert_true(seekDone); return; @@ -225,7 +225,7 @@ CESTER_TEST(cdlSeekP2to71, test_instance, return; } - int seekDone = seekTo(0, 2, 0); + int seekDone = seekPTo(0, 2, 0); if (!seekDone) { cester_assert_true(seekDone); return; @@ -295,7 +295,7 @@ CESTER_TEST(cdlSeekP2to99, test_instance, return; } - int seekDone = seekTo(0, 2, 0); + int seekDone = seekPTo(0, 2, 0); if (!seekDone) { cester_assert_true(seekDone); return; diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index fab02f25d..686470415 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -168,7 +168,38 @@ CESTER_BODY( return 1; } - static int seekTo(uint8_t minute, uint8_t second, uint8_t frame) { + static int seekPTo(uint8_t minute, uint8_t second, uint8_t frame) { + uint32_t imask = IMASK; + uint8_t cause; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = minute; + CDROM_REG2 = second; + CDROM_REG2 = frame; + CDROM_REG1 = CDL_SETLOC; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) return 0; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) return 0; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 2) return 0; + + IMASK = imask; + return 1; + } + + static int seekLTo(uint8_t minute, uint8_t second, uint8_t frame) { uint32_t imask = IMASK; uint8_t cause; From e57bc6aad4d695ea97e198c3f9b2b8fdc1ecb046 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 16:25:40 -0800 Subject: [PATCH 076/185] Fixing tests a bit, and adjusting emulator's behavior accordingly. --- src/core/cdrom.cc | 16 +++++++++-- src/core/cdrom.h | 2 ++ src/mips/tests/cdrom/cdlgetlocl.c | 48 ++++++++++++++++++++++++++++--- src/mips/tests/cdrom/cdlgetlocp.c | 19 ++++++------ src/mips/tests/cdrom/cester-hw.c | 2 +- 5 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index b90ffba58..54fda42c2 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -456,6 +456,7 @@ class CDRomImpl final : public PCSX::CDRom { m_currentPosition.s = 2; m_seekPosition.reset(); m_seekPosition.s = 2; + m_invalidLocL = false; memset(m_lastLocP, 0, sizeof(m_lastLocP)); schedule(2ms); break; @@ -493,8 +494,14 @@ class CDRomImpl final : public PCSX::CDRom { case 1: { // TODO: probably should error out if no disc or // lid open? - setResponse("TODOTODO"sv); - m_cause = Cause::Acknowledge; + if (m_invalidLocL) { + setResponse(getStatus() | 1); + appendResponse(0x80); + m_cause = Cause::Error; + } else { + setResponse(std::string_view((char *)m_lastLocL, sizeof(m_lastLocL))); + m_cause = Cause::Acknowledge; + } m_state = 0; m_command = 0; triggerIRQ(); @@ -610,6 +617,7 @@ class CDRomImpl final : public PCSX::CDRom { m_cause = Cause::Complete; setResponse(getStatus()); } + m_invalidLocL = true; m_state = 0; m_command = 0; triggerIRQ(); @@ -639,7 +647,8 @@ class CDRomImpl final : public PCSX::CDRom { } [[fallthrough]]; case 3: { - m_currentPosition = m_seekPosition; + MSF fudge = m_seekPosition - MSF{m_seekPosition.toLBA() / 32768}; + m_currentPosition = fudge; if (m_iso->getTrack(m_seekPosition) == 0) { m_cause = Cause::Error; setResponse(getStatus() | 4); @@ -648,6 +657,7 @@ class CDRomImpl final : public PCSX::CDRom { m_cause = Cause::Complete; setResponse(getStatus()); } + m_invalidLocL = true; m_state = 0; m_command = 0; triggerIRQ(); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index e6808a85e..6064a901f 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -126,6 +126,7 @@ class CDRom { bool m_gotAck = false; bool m_waitingAck = false; bool m_motorOn = false; + bool m_invalidLocL = false; enum class Status { STOPPED, READING_DATA, @@ -149,6 +150,7 @@ class CDRom { MSF m_currentPosition; MSF m_seekPosition; uint8_t m_lastLocP[8] = {0}; + uint8_t m_lastLocL[8] = {0}; private: friend class Widgets::IsoBrowser; diff --git a/src/mips/tests/cdrom/cdlgetlocl.c b/src/mips/tests/cdrom/cdlgetlocl.c index ce94b9f95..ce65c543a 100644 --- a/src/mips/tests/cdrom/cdlgetlocl.c +++ b/src/mips/tests/cdrom/cdlgetlocl.c @@ -60,12 +60,12 @@ CESTER_TEST(cdlGetLocL, test_instances, ramsyscall_printf("Basic getlocL, complete in %ius\n", completeTime); ) -CESTER_TEST(cdlGetLocLafterSeekL, test_instances, +CESTER_TEST(cdlGetLocLafterSeekP, test_instances, int resetDone = resetCDRom(); cester_assert_true(resetDone); if (!resetDone) return; - int seekDone = seekLTo(0x50, 0, 0); + int seekDone = seekPTo(0x50, 0, 0); if (!seekDone) { cester_assert_true(seekDone); return; @@ -87,7 +87,7 @@ CESTER_TEST(cdlGetLocLafterSeekL, test_instances, cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); - // Since we've done a seekL, without a read, we will actually + // Since we've done a seekP, without a read, we will actually // error out here, unlike the previous test. cester_assert_uint_eq(2, responseSize); cester_assert_uint_eq(3, response[0]); @@ -96,5 +96,45 @@ CESTER_TEST(cdlGetLocLafterSeekL, test_instances, // been seen to spike high from time to time. cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); - ramsyscall_printf("Basic getlocL after seekL, errored in %ius\n", errorTime); + ramsyscall_printf("Basic getlocL after seekP, errored in %ius\n", errorTime); +) + + +CESTER_TEST(cdlGetLocLafterSeekL, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + int seekDone = seekPTo(0x50, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCL; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Just like with the seekP, we will error out here, as + // there was no valid read performed. + cester_assert_uint_eq(2, responseSize); + cester_assert_uint_eq(3, response[0]); + cester_assert_uint_eq(0x80, response[1]); + // Typical value seems to be around 750us, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 7000); + ramsyscall_printf("Basic getlocL after seekL, complete in %ius\n", completeTime); ) diff --git a/src/mips/tests/cdrom/cdlgetlocp.c b/src/mips/tests/cdrom/cdlgetlocp.c index 35e5437b5..7b4a52e2f 100644 --- a/src/mips/tests/cdrom/cdlgetlocp.c +++ b/src/mips/tests/cdrom/cdlgetlocp.c @@ -91,7 +91,7 @@ CESTER_TEST(cdlGetLocPafterSeekP, test_instances, cester_assert_true(resetDone); if (!resetDone) return; - int seekDone = seekTo(0x50, 0, 0); + int seekDone = seekPTo(0x50, 0, 0); if (!seekDone) { cester_assert_true(seekDone); return; @@ -173,9 +173,12 @@ CESTER_TEST(cdlGetLocPafterSeekL, test_instances, cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); - // After a simple seekP, the head will hover around the seeked - // position, so the GetLocP will return values before that. Distance - // from the seeked position will be up to 50 frames around this location. + // After a simple seekL, the head will hover around the seeked + // position, so the GetLocP will return values around that. Distance + // from the seeked position will be up to 10 frames around this location, + // and sometimes a little bit after it too. It will be much more precise + // than seekP however, and most of the time, will be exactly at the + // seeked position. int inPregap = response.index == 0; uint32_t relative = MSF2LBA(btoi(response.m), btoi(response.s), btoi(response.f)); uint32_t absolute = MSF2LBA(btoi(response.am), btoi(response.as), btoi(response.af)); @@ -189,10 +192,10 @@ CESTER_TEST(cdlGetLocPafterSeekL, test_instances, cester_assert_uint_ge(onefifty, 150); cester_assert_uint_eq(inPregap, 0); cester_assert_uint_eq(response.index, 1); - cester_assert_uint_ge(absolute, 224950); - cester_assert_uint_lt(absolute, 225000); - cester_assert_uint_ge(relative, 224800); - cester_assert_uint_lt(relative, 224850); + cester_assert_uint_ge(absolute, 224990); + cester_assert_uint_le(absolute, 225005); + cester_assert_uint_ge(relative, 224840); + cester_assert_uint_le(relative, 224855); cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index 686470415..38dea57a0 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -216,7 +216,7 @@ CESTER_BODY( if (cause != 3) return 0; CDROM_REG0 = 0; - CDROM_REG1 = CDL_SEEKP; + CDROM_REG1 = CDL_SEEKL; waitCDRomIRQ(); cause = ackCDRomCause(); CDROM_REG1; From ba20cbe4a85d3c9b9cc47d0e818ee54a644fcb68 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 17:25:56 -0800 Subject: [PATCH 077/185] Adding track 5 tests, and reducing out-of-disc seek from 99 to 80, because the physical lens really doesn't like it. --- src/mips/tests/cdrom/cdlgetlocp.c | 124 +++++++++++++++++++++++++++++- src/mips/tests/cdrom/cdlseekl.c | 6 +- src/mips/tests/cdrom/cdlseekp.c | 6 +- 3 files changed, 126 insertions(+), 10 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgetlocp.c b/src/mips/tests/cdrom/cdlgetlocp.c index 7b4a52e2f..7258bed39 100644 --- a/src/mips/tests/cdrom/cdlgetlocp.c +++ b/src/mips/tests/cdrom/cdlgetlocp.c @@ -127,8 +127,8 @@ CESTER_TEST(cdlGetLocPafterSeekP, test_instances, } cester_assert_uint_eq(1, response.track); cester_assert_uint_ge(onefifty, 150); - cester_assert_uint_eq(inPregap, 0); - cester_assert_uint_eq(response.index, 1); + cester_assert_uint_eq(0, inPregap); + cester_assert_uint_eq(1, response.index); cester_assert_uint_ge(absolute, 224950); cester_assert_uint_lt(absolute, 225000); cester_assert_uint_ge(relative, 224800); @@ -190,8 +190,8 @@ CESTER_TEST(cdlGetLocPafterSeekL, test_instances, } cester_assert_uint_eq(1, response.track); cester_assert_uint_ge(onefifty, 150); - cester_assert_uint_eq(inPregap, 0); - cester_assert_uint_eq(response.index, 1); + cester_assert_uint_eq(0, inPregap); + cester_assert_uint_eq(1, response.index); cester_assert_uint_ge(absolute, 224990); cester_assert_uint_le(absolute, 225005); cester_assert_uint_ge(relative, 224840); @@ -208,3 +208,119 @@ CESTER_TEST(cdlGetLocPafterSeekL, test_instances, response.am, response.as, response.af, absolute ); ) + + +CESTER_TEST(cdlGetLocPinT5, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + int seekDone = seekPTo(0x70, 0x21, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + struct LocPResult response; + uint8_t responseSize = readResponse((uint8_t*)&response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Let's go inside of track 5, and see what we get. + int inPregap = response.index == 0; + uint32_t relative = MSF2LBA(btoi(response.m), btoi(response.s), btoi(response.f)); + uint32_t absolute = MSF2LBA(btoi(response.am), btoi(response.as), btoi(response.af)); + uint32_t start = absolute; + if (inPregap) { + start = absolute + relative; + } else { + start = absolute - relative; + } + cester_assert_uint_eq(5, response.track); + cester_assert_uint_ge(start, 316500); + cester_assert_uint_eq(0, inPregap); + cester_assert_uint_eq(1, response.index); + cester_assert_uint_ge(absolute, 316535); + cester_assert_uint_lt(absolute, 316575); + cester_assert_uint_ge(relative, 35); + cester_assert_uint_lt(relative, 75); + cester_assert_uint_eq(8, responseSize); + // Typical value seems to be around 1ms, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 7000); + ramsyscall_printf("Basic getlocP after seekP in track5's, complete in %ius\n", completeTime); + ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", + response.track, response.index, + response.m, response.s, response.f, relative, + response.am, response.as, response.af, absolute + ); +) + +CESTER_TEST(cdlGetLocPinT5Pregap, test_instances, + int resetDone = resetCDRom(); + cester_assert_true(resetDone); + if (!resetDone) return; + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + struct LocPResult response; + uint8_t responseSize = readResponse((uint8_t*)&response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // This time, the head is in the pregap of track 5. + int inPregap = response.index == 0; + uint32_t relative = MSF2LBA(btoi(response.m), btoi(response.s), btoi(response.f)); + uint32_t absolute = MSF2LBA(btoi(response.am), btoi(response.as), btoi(response.af)); + uint32_t start = absolute; + if (inPregap) { + start = absolute + relative; + } else { + start = absolute - relative; + } + cester_assert_uint_eq(5, response.track); + cester_assert_uint_ge(start, 316500); + cester_assert_uint_eq(1, inPregap); + cester_assert_uint_eq(0, response.index); + cester_assert_uint_ge(absolute, 316460); + cester_assert_uint_lt(absolute, 316500); + cester_assert_uint_lt(relative, 40); + cester_assert_uint_eq(8, responseSize); + // Typical value seems to be around 1ms, but has + // been seen to spike high from time to time. + cester_assert_uint_ge(completeTime, 500); + cester_assert_uint_lt(completeTime, 7000); + ramsyscall_printf("Basic getlocP after seekP in track5's pregap, complete in %ius\n", completeTime); + ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", + response.track, response.index, + response.m, response.s, response.f, relative, + response.am, response.as, response.af, absolute + ); +) diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c index e7eb5c1ee..4ca87db4c 100644 --- a/src/mips/tests/cdrom/cdlseekl.c +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -287,7 +287,7 @@ CESTER_TEST(cdlSeekL2to71, test_instance, IMASK = imask; ) -CESTER_TEST(cdlSeekL2to99, test_instance, +CESTER_TEST(cdlSeekL2to80, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -304,7 +304,7 @@ CESTER_TEST(cdlSeekL2to99, test_instance, return; } - int setLocDone = setLoc(0x99, 0, 0); + int setLocDone = setLoc(0x80, 0, 0); if (!setLocDone) { cester_assert_true(setLocDone); return; @@ -356,7 +356,7 @@ CESTER_TEST(cdlSeekL2to99, test_instance, // retry reading where there's clearly no information whatsoever. Will sometimes // fail in roughly 650ms, which is the seek time plus some minor retry. cester_assert_uint_ge(errorTime, 600000); - ramsyscall_printf("Basic seekL from 00:02:00 to 99:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); + ramsyscall_printf("Basic seekL from 00:02:00 to 80:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 27abb96d0..31a5a913a 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -284,7 +284,7 @@ CESTER_TEST(cdlSeekP2to71, test_instance, IMASK = imask; ) -CESTER_TEST(cdlSeekP2to99, test_instance, +CESTER_TEST(cdlSeekP2to80, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -301,7 +301,7 @@ CESTER_TEST(cdlSeekP2to99, test_instance, return; } - int setLocDone = setLoc(0x99, 0, 0); + int setLocDone = setLoc(0x80, 0, 0); if (!setLocDone) { cester_assert_true(setLocDone); return; @@ -353,7 +353,7 @@ CESTER_TEST(cdlSeekP2to99, test_instance, // retry reading where there's clearly no information whatsoever. Will sometimes // fail in roughly 650ms, which is the seek time plus some minor retry. cester_assert_uint_ge(errorTime, 600000); - ramsyscall_printf("Basic seekP from 00:02:00 to 99:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); + ramsyscall_printf("Basic seekP from 00:02:00 to 80:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); IMASK = imask; ) From 5cbb19646faf51cb8dfc854db780f57761b2bb94 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 18:28:50 -0800 Subject: [PATCH 078/185] Fixing pregap relative position calculation (durr) --- src/cdrom/cdriso.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cdrom/cdriso.cc b/src/cdrom/cdriso.cc index d1912bf40..c22be656e 100644 --- a/src/cdrom/cdriso.cc +++ b/src/cdrom/cdriso.cc @@ -448,7 +448,7 @@ bool PCSX::CDRIso::getLocP(const PCSX::IEC60908b::MSF msf, uint8_t locP[8]) { locP[1] = inPregap ? 0 : 1; IEC60908b::MSF relative; if (inPregap) { - m_ti[track].start - msf; + relative = m_ti[track].start - msf; } else { relative = msf - m_ti[track].start; } From fd722d0d5a159f3552f278e647475caffb4f31b9 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 19:27:32 -0800 Subject: [PATCH 079/185] Adjusting tiings a bit, and adding setMode tests. --- src/mips/tests/cdrom/cdlseekl.c | 6 +- src/mips/tests/cdrom/cdlseekp.c | 8 +- src/mips/tests/cdrom/cdlsetmode.c | 151 ++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdrom.c | 1 + 4 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 src/mips/tests/cdrom/cdlsetmode.c diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c index 4ca87db4c..3712fa335 100644 --- a/src/mips/tests/cdrom/cdlseekl.c +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -205,7 +205,7 @@ CESTER_TEST(cdlSeekL2to4, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); + cester_assert_uint_lt(ackTime, 2500); // It'd be difficult to put an interval check here, as the seek time will vary // a lot depending on the status of the drive, but it should probably be // at least 120ms, and more likely 170ms. @@ -277,7 +277,7 @@ CESTER_TEST(cdlSeekL2to71, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); + cester_assert_uint_lt(ackTime, 2500); // The seekL won't be successful when targeting a sector past the end of the // data track, but it should still take a while to complete, because it'll // keep retrying reading data where there's none. Roughly 4s. @@ -350,7 +350,7 @@ CESTER_TEST(cdlSeekL2to80, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); + cester_assert_uint_lt(ackTime, 2500); // The seekL won't be successful when targeting a sector past the end of the // disc. The failure can be faster than the previous test, because it won't // retry reading where there's clearly no information whatsoever. Will sometimes diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 31a5a913a..09cee29f0 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -82,7 +82,7 @@ CESTER_TEST(cdlSeekP, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); + cester_assert_uint_lt(ackTime, 2500); // Timings here won't really be relevant, as the CDRom's head will be hovering // already around the right place, so it's mostly a no-op to seek there, but // can vary a lot between 2ms and 500ms as the head is moving and re-aligning. @@ -205,7 +205,7 @@ CESTER_TEST(cdlSeekP2to4, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); + cester_assert_uint_lt(ackTime, 2500); // It'd be difficult to put an interval check here, as the seek time will vary // a lot depending on the status of the drive, but it should probably be // at least 100ms, and more likely 150ms. @@ -276,7 +276,7 @@ CESTER_TEST(cdlSeekP2to71, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); + cester_assert_uint_lt(ackTime, 2500); // This is a pretty long distance seek, which will take at least a full second. cester_assert_uint_ge(completeTime, 1000000); ramsyscall_printf("Basic seekP from 00:02:00 to 71:00:00: ack in %ius, complete in %ius\n", ackTime, completeTime); @@ -347,7 +347,7 @@ CESTER_TEST(cdlSeekP2to80, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2000); + cester_assert_uint_lt(ackTime, 2500); // The seekP won't be successful when targeting a sector past the end of the // disc. The failure can be faster than the previous test, because it won't // retry reading where there's clearly no information whatsoever. Will sometimes diff --git a/src/mips/tests/cdrom/cdlsetmode.c b/src/mips/tests/cdrom/cdlsetmode.c new file mode 100644 index 000000000..bf8b5f1e4 --- /dev/null +++ b/src/mips/tests/cdrom/cdlsetmode.c @@ -0,0 +1,151 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlSetMode, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x80; + CDROM_REG1 = CDL_SETMODE; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Typical value seems to be around 2ms, but varies a lot. + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic setMode: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSetModeWithoutArgs, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SETMODE; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Typical value seems to be around 750us. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("No args setMode: errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSetModeWithTooManyArgs, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 0x80; + CDROM_REG2 = 0x80; + CDROM_REG2 = 0x80; + CDROM_REG2 = 0x80; + CDROM_REG1 = CDL_SETMODE; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + // Typical value seems to be around 750us. + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("No args setMode: errored in %ius\n", errorTime); + + IMASK = imask; +) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 0f176950c..c8552b099 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -44,4 +44,5 @@ SOFTWARE. #include "cdlseekl.c" #include "cdlseekp.c" #include "cdlsetloc.c" +#include "cdlsetmode.c" #include "invalid.c" From e6a37fea5969280691e3bc328dea74c20301d406 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 19:47:20 -0800 Subject: [PATCH 080/185] Adding a basic setMode handler. --- src/core/cdrom.cc | 25 ++++++++++++++++++++++++- src/core/cdrom.h | 1 + 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 54fda42c2..483d15920 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -102,6 +102,7 @@ class CDRomImpl final : public PCSX::CDRom { m_seekPosition.reset(); m_gotAck = false; m_waitingAck = false; + m_speed = Speed::Simple; } void interrupt() override { @@ -457,6 +458,7 @@ class CDRomImpl final : public PCSX::CDRom { m_seekPosition.reset(); m_seekPosition.s = 2; m_invalidLocL = false; + m_speed = Speed::Simple; memset(m_lastLocP, 0, sizeof(m_lastLocP)); schedule(2ms); break; @@ -484,6 +486,27 @@ class CDRomImpl final : public PCSX::CDRom { } } + // Command 14 + void cdlSetMode() { + switch (m_state) { + case 0: + m_state = 1; + schedule(750us); + break; + case 1: { + uint8_t mode = m_paramFIFO[0]; + // TODO: add the rest of the mode bits. + m_speed = mode & 0x80 ? Speed::Double : Speed::Simple; + setResponse(getStatus()); + m_cause = Cause::Acknowledge; + m_paramFIFOSize = 0; + m_state = 0; + m_command = 0; + triggerIRQ(); + } break; + } + } + // Command 16. void cdlGetLocL() { switch (m_state) { @@ -704,7 +727,7 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlUnk, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 12 + &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlSetMode, &CDRomImpl::cdlUnk, // 12 &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, &CDRomImpl::cdlUnk, &CDRomImpl::cdlGetTN, // 16 &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, &CDRomImpl::cdlUnk, // 20 &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 6064a901f..a05b7d3a3 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -151,6 +151,7 @@ class CDRom { MSF m_seekPosition; uint8_t m_lastLocP[8] = {0}; uint8_t m_lastLocL[8] = {0}; + enum class Speed { Simple, Double } m_speed; private: friend class Widgets::IsoBrowser; From 6c2937eafb38b95a66430f08c97bd622969671fd Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 20:39:25 -0800 Subject: [PATCH 081/185] Harmonizing timings and names. --- src/mips/tests/cdrom/cdlgetlocl.c | 16 ++++++------- src/mips/tests/cdrom/cdlgetlocp.c | 40 +++++++++++++++---------------- src/mips/tests/cdrom/cdlinit.c | 10 ++++---- src/mips/tests/cdrom/cdlseekl.c | 8 +++---- src/mips/tests/cdrom/cdlseekp.c | 10 ++++---- src/mips/tests/cdrom/cdlsetloc.c | 22 ++++++++--------- 6 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgetlocl.c b/src/mips/tests/cdrom/cdlgetlocl.c index ce65c543a..3ff4fa69a 100644 --- a/src/mips/tests/cdrom/cdlgetlocl.c +++ b/src/mips/tests/cdrom/cdlgetlocl.c @@ -34,7 +34,7 @@ CESTER_TEST(cdlGetLocL, test_instances, initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCL; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; @@ -55,9 +55,9 @@ CESTER_TEST(cdlGetLocL, test_instances, cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 7000); - ramsyscall_printf("Basic getlocL, complete in %ius\n", completeTime); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getlocL, ack in %ius\n", ackTime); ) CESTER_TEST(cdlGetLocLafterSeekP, test_instances, @@ -114,7 +114,7 @@ CESTER_TEST(cdlGetLocLafterSeekL, test_instances, initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCL; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; @@ -134,7 +134,7 @@ CESTER_TEST(cdlGetLocLafterSeekL, test_instances, cester_assert_uint_eq(0x80, response[1]); // Typical value seems to be around 750us, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 7000); - ramsyscall_printf("Basic getlocL after seekL, complete in %ius\n", completeTime); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getlocL after seekL, ack in %ius\n", ackTime); ) diff --git a/src/mips/tests/cdrom/cdlgetlocp.c b/src/mips/tests/cdrom/cdlgetlocp.c index 7258bed39..23d7535cd 100644 --- a/src/mips/tests/cdrom/cdlgetlocp.c +++ b/src/mips/tests/cdrom/cdlgetlocp.c @@ -34,7 +34,7 @@ CESTER_TEST(cdlGetLocP, test_instances, initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCP; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; struct LocPResult response; @@ -76,9 +76,9 @@ CESTER_TEST(cdlGetLocP, test_instances, cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 6500); - ramsyscall_printf("Basic getlocP, complete in %ius\n", completeTime); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getlocP, ack in %ius\n", ackTime); ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", response.track, response.index, response.m, response.s, response.f, relative, @@ -100,7 +100,7 @@ CESTER_TEST(cdlGetLocPafterSeekP, test_instances, initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCP; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; struct LocPResult response; @@ -136,9 +136,9 @@ CESTER_TEST(cdlGetLocPafterSeekP, test_instances, cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 7000); - ramsyscall_printf("Basic getlocP after seekP, complete in %ius\n", completeTime); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getlocP after seekP, ack in %ius\n", ackTime); ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", response.track, response.index, response.m, response.s, response.f, relative, @@ -160,7 +160,7 @@ CESTER_TEST(cdlGetLocPafterSeekL, test_instances, initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCP; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; struct LocPResult response; @@ -199,9 +199,9 @@ CESTER_TEST(cdlGetLocPafterSeekL, test_instances, cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 7000); - ramsyscall_printf("Basic getlocP after seekL, complete in %ius\n", completeTime); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getlocP after seekL, ack in %ius\n", ackTime); ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", response.track, response.index, response.m, response.s, response.f, relative, @@ -224,7 +224,7 @@ CESTER_TEST(cdlGetLocPinT5, test_instances, initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCP; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; struct LocPResult response; @@ -258,9 +258,9 @@ CESTER_TEST(cdlGetLocPinT5, test_instances, cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 7000); - ramsyscall_printf("Basic getlocP after seekP in track5's, complete in %ius\n", completeTime); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getlocP after seekP in track5's, ack in %ius\n", ackTime); ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", response.track, response.index, response.m, response.s, response.f, relative, @@ -282,7 +282,7 @@ CESTER_TEST(cdlGetLocPinT5Pregap, test_instances, initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCP; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; struct LocPResult response; @@ -315,9 +315,9 @@ CESTER_TEST(cdlGetLocPinT5Pregap, test_instances, cester_assert_uint_eq(8, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 7000); - ramsyscall_printf("Basic getlocP after seekP in track5's pregap, complete in %ius\n", completeTime); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getlocP after seekP in track5's pregap, ack in %ius\n", ackTime); ramsyscall_printf("Full response: track: %02x, index: %02x, relative: %02x:%02x:%02x(%2i), absolute: %02x:%02x:%02x(%2i)\n", response.track, response.index, response.m, response.s, response.f, relative, diff --git a/src/mips/tests/cdrom/cdlinit.c b/src/mips/tests/cdrom/cdlinit.c index 553a17b32..d071de242 100644 --- a/src/mips/tests/cdrom/cdlinit.c +++ b/src/mips/tests/cdrom/cdlinit.c @@ -71,8 +71,8 @@ CESTER_TEST(cdlInit, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); // Typical value seems to be around 2ms. - cester_assert_uint_ge(ackTime, 800); - cester_assert_uint_lt(ackTime, 5000); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); // These may be a bit flaky on real hardware, depending on the motors status when starting. // Typical value seems to be around 120ms. cester_assert_uint_ge(completeTime, 50000); @@ -129,8 +129,8 @@ CESTER_TEST(cdlInitDelayed, test_instance, cester_assert_uint_eq(0x18, ctrl1); cester_assert_uint_eq(0x18, ctrl2); // This still takes about 2ms. - cester_assert_uint_ge(ackTime, 800); - cester_assert_uint_lt(ackTime, 5000); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); // Since the initialization completes in the background of the controller // waiting its ack, we're really only measuring the roundtrip of the // communication between the CPU and the mechacon. It typically takes 350us @@ -195,7 +195,7 @@ CESTER_TEST(cdlInitWithArgs, test_instance, cester_assert_uint_eq(0x18, ctrl4); // Typical value seems to be around 1ms. cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 2000); + cester_assert_uint_lt(errorTime, 7000); // Typical value seems to be around 1.5ms. cester_assert_uint_ge(ackTime, 1000); cester_assert_uint_lt(ackTime, 3500); diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c index 3712fa335..11d8157f0 100644 --- a/src/mips/tests/cdrom/cdlseekl.c +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -137,7 +137,7 @@ CESTER_TEST(cdlSeekLwithArgs, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 2000); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Too many args seekL, errored in %ius\n", errorTime); IMASK = imask; @@ -205,7 +205,7 @@ CESTER_TEST(cdlSeekL2to4, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 7000); // It'd be difficult to put an interval check here, as the seek time will vary // a lot depending on the status of the drive, but it should probably be // at least 120ms, and more likely 170ms. @@ -277,7 +277,7 @@ CESTER_TEST(cdlSeekL2to71, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 7000); // The seekL won't be successful when targeting a sector past the end of the // data track, but it should still take a while to complete, because it'll // keep retrying reading data where there's none. Roughly 4s. @@ -350,7 +350,7 @@ CESTER_TEST(cdlSeekL2to80, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 7000); // The seekL won't be successful when targeting a sector past the end of the // disc. The failure can be faster than the previous test, because it won't // retry reading where there's clearly no information whatsoever. Will sometimes diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 09cee29f0..3e948118a 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -82,7 +82,7 @@ CESTER_TEST(cdlSeekP, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 7000); // Timings here won't really be relevant, as the CDRom's head will be hovering // already around the right place, so it's mostly a no-op to seek there, but // can vary a lot between 2ms and 500ms as the head is moving and re-aligning. @@ -137,7 +137,7 @@ CESTER_TEST(cdlSeekPwithArgs, test_instance, cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 2000); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Too many args seekP, errored in %ius\n", errorTime); IMASK = imask; @@ -205,7 +205,7 @@ CESTER_TEST(cdlSeekP2to4, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 7000); // It'd be difficult to put an interval check here, as the seek time will vary // a lot depending on the status of the drive, but it should probably be // at least 100ms, and more likely 150ms. @@ -276,7 +276,7 @@ CESTER_TEST(cdlSeekP2to71, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 7000); // This is a pretty long distance seek, which will take at least a full second. cester_assert_uint_ge(completeTime, 1000000); ramsyscall_printf("Basic seekP from 00:02:00 to 71:00:00: ack in %ius, complete in %ius\n", ackTime, completeTime); @@ -347,7 +347,7 @@ CESTER_TEST(cdlSeekP2to80, test_instance, cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_ge(ackTime, 500); - cester_assert_uint_lt(ackTime, 2500); + cester_assert_uint_lt(ackTime, 7000); // The seekP won't be successful when targeting a sector past the end of the // disc. The failure can be faster than the previous test, because it won't // retry reading where there's clearly no information whatsoever. Will sometimes diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index c642820ad..58eecf416 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -37,7 +37,7 @@ CESTER_TEST(cdlSetLoc, test_instances, CDROM_REG2 = 2; CDROM_REG2 = 0; CDROM_REG1 = CDL_SETLOC; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; uint8_t response[16]; @@ -54,8 +54,8 @@ CESTER_TEST(cdlSetLoc, test_instances, cester_assert_uint_eq(1, responseSize); // Typical value seems to be around 1ms, but has // been seen to spike high from time to time. - cester_assert_uint_ge(completeTime, 500); - cester_assert_uint_lt(completeTime, 6500); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic setloc to 00:02:00, complete in %ius\n", completeTime); ) @@ -84,7 +84,7 @@ CESTER_TEST(cdlSetLocNoArgs, test_instances, cester_assert_uint_eq(0x20, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 6500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Invalid setloc with no args, errored in %ius\n", errorTime); ) @@ -141,11 +141,11 @@ CESTER_TEST(cdlSetLocMultiple, test_instances, // vary regardless of the location, but can // still spike to 6ms from time to time. cester_assert_uint_ge(time1, 500); - cester_assert_uint_lt(time1, 6500); + cester_assert_uint_lt(time1, 7000); cester_assert_uint_ge(time2, 500); - cester_assert_uint_lt(time2, 6500); + cester_assert_uint_lt(time2, 7000); cester_assert_uint_ge(time3, 500); - cester_assert_uint_lt(time3, 6500); + cester_assert_uint_lt(time3, 7000); ramsyscall_printf("Multiple setloc to 00:02:00, complete in %ius, %ius, %ius\n", time1, time2, time3); ) @@ -177,7 +177,7 @@ CESTER_TEST(cdlSetLocInvalid1, test_instances, cester_assert_uint_eq(0x10, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 6500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Invalid setloc to 00:02:2a, errored in %ius\n", errorTime); ) @@ -209,7 +209,7 @@ CESTER_TEST(cdlSetLocInvalid2, test_instances, cester_assert_uint_eq(0x10, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 6500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Invalid setloc to 00:02:79, errored in %ius\n", errorTime); ) @@ -242,7 +242,7 @@ CESTER_TEST(cdlSetLocTooManyArgs, test_instances, cester_assert_uint_eq(0x20, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 6500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Invalid setloc with too many args, errored in %ius\n", errorTime); ) @@ -275,7 +275,7 @@ CESTER_TEST(cdlSetLocTooManyArgsAndInvalid, test_instances, cester_assert_uint_eq(0x20, response[1]); cester_assert_uint_eq(2, responseSize); cester_assert_uint_ge(errorTime, 500); - cester_assert_uint_lt(errorTime, 6500); + cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Invalid setloc with too many invalid args, errored in %ius\n", errorTime); ) From 595f4bfbd2cae5c23cc431156e320c136baebccd Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 20:45:31 -0800 Subject: [PATCH 082/185] Missed one. --- src/mips/tests/cdrom/cdlsetloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index 58eecf416..93843f235 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -56,7 +56,7 @@ CESTER_TEST(cdlSetLoc, test_instances, // been seen to spike high from time to time. cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic setloc to 00:02:00, complete in %ius\n", completeTime); + ramsyscall_printf("Basic setloc to 00:02:00, ack in %ius\n", ackTime); ) CESTER_TEST(cdlSetLocNoArgs, test_instances, From 166a1b995c8ed73a4411279f4470fde0ef2157dc Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 21:05:27 -0800 Subject: [PATCH 083/185] Speeding up some tests. --- src/mips/tests/cdrom/cdlgetlocl.c | 18 ++++++++----- src/mips/tests/cdrom/cdlgetlocp.c | 30 ++++++++++++++-------- src/mips/tests/cdrom/cdlsetloc.c | 42 ++++++++++++++++++++----------- 3 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgetlocl.c b/src/mips/tests/cdrom/cdlgetlocl.c index 3ff4fa69a..8b4f2894a 100644 --- a/src/mips/tests/cdrom/cdlgetlocl.c +++ b/src/mips/tests/cdrom/cdlgetlocl.c @@ -28,8 +28,10 @@ SOFTWARE. CESTER_TEST(cdlGetLocL, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -62,8 +64,10 @@ CESTER_TEST(cdlGetLocL, test_instances, CESTER_TEST(cdlGetLocLafterSeekP, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } int seekDone = seekPTo(0x50, 0, 0); if (!seekDone) { @@ -102,8 +106,10 @@ CESTER_TEST(cdlGetLocLafterSeekP, test_instances, CESTER_TEST(cdlGetLocLafterSeekL, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } int seekDone = seekPTo(0x50, 0, 0); if (!seekDone) { diff --git a/src/mips/tests/cdrom/cdlgetlocp.c b/src/mips/tests/cdrom/cdlgetlocp.c index 23d7535cd..8d3bf7eb9 100644 --- a/src/mips/tests/cdrom/cdlgetlocp.c +++ b/src/mips/tests/cdrom/cdlgetlocp.c @@ -28,8 +28,10 @@ SOFTWARE. CESTER_TEST(cdlGetLocP, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -88,8 +90,10 @@ CESTER_TEST(cdlGetLocP, test_instances, CESTER_TEST(cdlGetLocPafterSeekP, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } int seekDone = seekPTo(0x50, 0, 0); if (!seekDone) { @@ -148,8 +152,10 @@ CESTER_TEST(cdlGetLocPafterSeekP, test_instances, CESTER_TEST(cdlGetLocPafterSeekL, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } int seekDone = seekLTo(0x50, 0, 0); if (!seekDone) { @@ -212,8 +218,10 @@ CESTER_TEST(cdlGetLocPafterSeekL, test_instances, CESTER_TEST(cdlGetLocPinT5, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } int seekDone = seekPTo(0x70, 0x21, 0); if (!seekDone) { @@ -270,8 +278,10 @@ CESTER_TEST(cdlGetLocPinT5, test_instances, CESTER_TEST(cdlGetLocPinT5Pregap, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } int seekDone = seekPTo(0x70, 0x19, 0x73); if (!seekDone) { diff --git a/src/mips/tests/cdrom/cdlsetloc.c b/src/mips/tests/cdrom/cdlsetloc.c index 93843f235..5e57c18c0 100644 --- a/src/mips/tests/cdrom/cdlsetloc.c +++ b/src/mips/tests/cdrom/cdlsetloc.c @@ -28,8 +28,10 @@ SOFTWARE. CESTER_TEST(cdlSetLoc, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -61,8 +63,10 @@ CESTER_TEST(cdlSetLoc, test_instances, CESTER_TEST(cdlSetLocNoArgs, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -91,8 +95,10 @@ CESTER_TEST(cdlSetLocNoArgs, test_instances, CESTER_TEST(cdlSetLocMultiple, test_instances, int resetDone = resetCDRom(); uint8_t cause; - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -151,8 +157,10 @@ CESTER_TEST(cdlSetLocMultiple, test_instances, CESTER_TEST(cdlSetLocInvalid1, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -183,8 +191,10 @@ CESTER_TEST(cdlSetLocInvalid1, test_instances, CESTER_TEST(cdlSetLocInvalid2, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -215,8 +225,10 @@ CESTER_TEST(cdlSetLocInvalid2, test_instances, CESTER_TEST(cdlSetLocTooManyArgs, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; @@ -248,8 +260,10 @@ CESTER_TEST(cdlSetLocTooManyArgs, test_instances, CESTER_TEST(cdlSetLocTooManyArgsAndInvalid, test_instances, int resetDone = resetCDRom(); - cester_assert_true(resetDone); - if (!resetDone) return; + if (!resetDone) { + cester_assert_true(resetDone); + return; + } initializeTime(); CDROM_REG0 = 0; From 76d6c313608a9bc4cedf927400c330d6b6090dee Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 21:05:43 -0800 Subject: [PATCH 084/185] Adding basic ReadN test. --- src/mips/tests/cdrom/cdlreadn.c | 113 ++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdrom.c | 1 + 2 files changed, 114 insertions(+) create mode 100644 src/mips/tests/cdrom/cdlreadn.c diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c new file mode 100644 index 000000000..9e7c50abc --- /dev/null +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -0,0 +1,113 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlReadN, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + ramsyscall_printf("Basic single full sector readN at 00:02:16, ack1 in %ius, ready in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, ackTime2, completeTime); +) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index c8552b099..77d4713eb 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -41,6 +41,7 @@ SOFTWARE. #include "cdlgettd.c" #include "cdlgettn.c" #include "cdlinit.c" +#include "cdlreadn.c" #include "cdlseekl.c" #include "cdlseekp.c" #include "cdlsetloc.c" From eec231af75ebaf20bcc5c7966b4b969037b3064a Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 23:14:07 -0800 Subject: [PATCH 085/185] More ReadN tests. --- src/mips/tests/cdrom/cdlreadn.c | 412 ++++++++++++++++++++++++++++++- src/mips/tests/cdrom/cdrom.c | 2 + src/mips/tests/cdrom/cester-hw.c | 38 ++- 3 files changed, 448 insertions(+), 4 deletions(-) diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c index 9e7c50abc..1364265c7 100644 --- a/src/mips/tests/cdrom/cdlreadn.c +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -26,13 +26,387 @@ SOFTWARE. // clang-format off -CESTER_TEST(cdlReadN, test_instances, +CESTER_TEST(cdlReadN1x, test_instances, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); return; } + // Mode after reset is undefined technically, + // but seems to be using raw mode. Let's make + // sure it's a known value. + int setModeDone = setMode(0); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + uint32_t size = 0; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + while ((CDROM_REG0 & 0x40) == 0); + while (((CDROM_REG0 & 0x40) != 0) && (size < 6)) { + sector[size++] = CDROM_REG2; + } + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Pausing at 1x is ~70ms + cester_assert_uint_ge(completeTime, 65000); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + cester_assert_uint_eq(6, size); + ramsyscall_printf("Basic single 6 bytes readN @1x at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadN1xwithDMA, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + // Mode after reset is undefined technically, + // but seems to be using raw mode. Let's make + // sure it's a known value. + int setModeDone = setMode(0); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + uint32_t dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x00880000; + DICR = dicr; + DPCR |= 0x8000; + DMA_CTRL[DMA_CDROM].MADR = (uintptr_t)sector; + DMA_CTRL[DMA_CDROM].BCR = (2048 >> 2) | 0x10000; + DMA_CTRL[DMA_CDROM].CHCR = 0x11000000; + + while ((DMA_CTRL[DMA_CDROM].CHCR & 0x01000000) != 0); + dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x88000000; + DICR = dicr; + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Pausing at 1x is ~70ms + cester_assert_uint_ge(completeTime, 65000); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + ramsyscall_printf("Basic single full sector readN @1x with DMA at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadN2x, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + // Mode after reset is undefined technically, + // but seems to be using raw mode. Let's make + // sure it's a known value. + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + uint32_t size = 0; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + while ((CDROM_REG0 & 0x40) == 0); + while (((CDROM_REG0 & 0x40) != 0) && (size < 6)) { + sector[size++] = CDROM_REG2; + } + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Switching speed is roughly 650ms for the speed up, + // and then this also contains the seeking time. + cester_assert_uint_ge(readyTime, 500000); + // Pausing at 2x is ~35ms + cester_assert_uint_ge(completeTime, 32500); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + cester_assert_uint_eq(6, size); + ramsyscall_printf("Basic single 6 bytes readN @2x at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadN2xwithDMA, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + // Mode after reset is undefined technically, + // but seems to be using raw mode. Let's make + // sure it's a known value. + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + int setLocDone = setLoc(0, 2, 0x16); if (!setLocDone) { cester_assert_true(setLocDone); @@ -60,6 +434,29 @@ CESTER_TEST(cdlReadN, test_instances, CDROM_REG0 = 1; uint8_t cause2b = CDROM_REG3_UC; + initializeTime(); + uint8_t sector[2048]; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + uint32_t dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x00880000; + DICR = dicr; + DPCR |= 0x8000; + DMA_CTRL[DMA_CDROM].MADR = (uintptr_t)sector; + DMA_CTRL[DMA_CDROM].BCR = (2048 >> 2) | 0x10000; + DMA_CTRL[DMA_CDROM].CHCR = 0x11000000; + + while ((DMA_CTRL[DMA_CDROM].CHCR & 0x01000000) != 0); + dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x88000000; + DICR = dicr; + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_PAUSE; @@ -109,5 +506,16 @@ CESTER_TEST(cdlReadN, test_instances, cester_assert_uint_lt(ackTime1, 7000); cester_assert_uint_ge(ackTime2, 500); cester_assert_uint_lt(ackTime2, 7000); - ramsyscall_printf("Basic single full sector readN at 00:02:16, ack1 in %ius, ready in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, ackTime2, completeTime); + // Switching speed is roughly 650ms for the speed up, + // and then this also contains the seeking time. + cester_assert_uint_ge(readyTime, 500000); + // Pausing at 2x is ~35ms + cester_assert_uint_ge(completeTime, 32500); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + ramsyscall_printf("Basic single full sector readN @2x with DMA at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); ) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 77d4713eb..c74180704 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -25,8 +25,10 @@ SOFTWARE. */ #include "common/hardware/cdrom.h" +#include "common/hardware/dma.h" #include "common/hardware/hwregs.h" #include "common/hardware/irq.h" +#include "common/syscalls/syscalls.h" #undef unix #define CESTER_NO_SIGNAL diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index 38dea57a0..f2421ad63 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -31,8 +31,6 @@ SOFTWARE. #include -#include "common/syscalls/syscalls.h" - CESTER_BODY( static int s_interruptsWereEnabled = 0; static uint16_t s_oldMode = 0; @@ -229,12 +227,48 @@ CESTER_BODY( IMASK = imask; return 1; } + + int setMode(uint8_t mode) { + uint32_t imask = IMASK; + uint8_t cause; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = mode; + CDROM_REG1 = CDL_SETMODE; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) return 0; + + IMASK = imask; + return 1; + } + + uint8_t getCtrl() { + uint32_t imask = IMASK; + uint8_t cause; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + waitCDRomIRQ(); + ackCDRomCause(); + uint8_t ctrl = CDROM_REG1; + + IMASK = imask; + return ctrl; + } ) CESTER_BEFORE_ALL(cpu_tests, s_interruptsWereEnabled = enterCriticalSection(); s_oldMode = COUNTERS[1].mode; COUNTERS[1].mode = 0x0100; + SBUS_DEV5_CTRL = 0x20943; + SBUS_COM_CTRL = 0x132c; ) CESTER_AFTER_ALL(cpu_tests, From 7387d6b3a3fb7a03b2db99c6a94375ebfb5a2e4d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 23:15:28 -0800 Subject: [PATCH 086/185] Properly resetting lid status bit. --- src/core/cdrom.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 483d15920..c478c7065 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -160,11 +160,11 @@ class CDRomImpl final : public PCSX::CDRom { void appendResponse(uint8_t response) { m_responseFIFO[m_responseFIFOSize++] = response; } - uint8_t getStatus() { + uint8_t getStatus(bool resetLid = false) { bool lidOpen = isLidOpen(); + if (resetLid && !lidOpen) m_wasLidOpened = false; uint8_t v1 = m_motorOn && !lidOpen ? 0x02 : 0; uint8_t v4 = m_wasLidOpened ? 0x10 : 0; - if (!lidOpen) m_wasLidOpened = false; uint8_t v567 = 0; switch (m_status) { case Status::READING_DATA: @@ -406,7 +406,7 @@ class CDRomImpl final : public PCSX::CDRom { schedule(750us); break; case 1: { - setResponse(getStatus()); + setResponse(getStatus(true)); m_cause = Cause::Acknowledge; m_paramFIFOSize = 0; m_state = 0; From 2e96bb3e538c615aac00d841a5aa35a70a7d3b43 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 23:24:54 -0800 Subject: [PATCH 087/185] Adding more info in the comments. --- src/mips/tests/cdrom/cdlreadn.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c index 1364265c7..f1aa4ef2b 100644 --- a/src/mips/tests/cdrom/cdlreadn.c +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -377,7 +377,8 @@ CESTER_TEST(cdlReadN2x, test_instances, cester_assert_uint_ge(ackTime2, 500); cester_assert_uint_lt(ackTime2, 7000); // Switching speed is roughly 650ms for the speed up, - // and then this also contains the seeking time. + // and then this also contains the seeking time, and + // the time to read the first sector, which is 6.66ms cester_assert_uint_ge(readyTime, 500000); // Pausing at 2x is ~35ms cester_assert_uint_ge(completeTime, 32500); @@ -507,7 +508,8 @@ CESTER_TEST(cdlReadN2xwithDMA, test_instances, cester_assert_uint_ge(ackTime2, 500); cester_assert_uint_lt(ackTime2, 7000); // Switching speed is roughly 650ms for the speed up, - // and then this also contains the seeking time. + // and then this also contains the seeking time, and + // the time to read the first sector, which is 6.66ms cester_assert_uint_ge(readyTime, 500000); // Pausing at 2x is ~35ms cester_assert_uint_ge(completeTime, 32500); From 1de118bc9842d11d54cc77c2cf60a06e3d1dd482 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 26 Dec 2022 23:42:16 -0800 Subject: [PATCH 088/185] Properly adjusting relative times. --- src/mips/tests/cdrom/cdlreadn.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c index f1aa4ef2b..04b574764 100644 --- a/src/mips/tests/cdrom/cdlreadn.c +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -60,7 +60,7 @@ CESTER_TEST(cdlReadN1x, test_instances, CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; - uint32_t readyTime = waitCDRomIRQ(); + uint32_t readyTime = waitCDRomIRQ() - ackTime1; uint8_t cause2 = ackCDRomCause(); uint8_t ctrl3 = CDROM_REG0 & ~3; uint8_t response2[16]; @@ -95,7 +95,7 @@ CESTER_TEST(cdlReadN1x, test_instances, CDROM_REG0 = 1; uint8_t cause3b = CDROM_REG3_UC; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t completeTime = waitCDRomIRQ() - ackTime2; uint8_t cause4 = ackCDRomCause(); uint8_t ctrl7 = CDROM_REG0 & ~3; uint8_t response4[16]; @@ -178,7 +178,7 @@ CESTER_TEST(cdlReadN1xwithDMA, test_instances, CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; - uint32_t readyTime = waitCDRomIRQ(); + uint32_t readyTime = waitCDRomIRQ() - ackTime1; uint8_t cause2 = ackCDRomCause(); uint8_t ctrl3 = CDROM_REG0 & ~3; uint8_t response2[16]; @@ -222,7 +222,7 @@ CESTER_TEST(cdlReadN1xwithDMA, test_instances, CDROM_REG0 = 1; uint8_t cause3b = CDROM_REG3_UC; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t completeTime = waitCDRomIRQ() - ackTime2; uint8_t cause4 = ackCDRomCause(); uint8_t ctrl7 = CDROM_REG0 & ~3; uint8_t response4[16]; @@ -304,7 +304,7 @@ CESTER_TEST(cdlReadN2x, test_instances, CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; - uint32_t readyTime = waitCDRomIRQ(); + uint32_t readyTime = waitCDRomIRQ() - ackTime1; uint8_t cause2 = ackCDRomCause(); uint8_t ctrl3 = CDROM_REG0 & ~3; uint8_t response2[16]; @@ -339,7 +339,7 @@ CESTER_TEST(cdlReadN2x, test_instances, CDROM_REG0 = 1; uint8_t cause3b = CDROM_REG3_UC; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t completeTime = waitCDRomIRQ() - ackTime2; uint8_t cause4 = ackCDRomCause(); uint8_t ctrl7 = CDROM_REG0 & ~3; uint8_t response4[16]; @@ -426,7 +426,7 @@ CESTER_TEST(cdlReadN2xwithDMA, test_instances, CDROM_REG0 = 1; uint8_t cause1b = CDROM_REG3_UC; - uint32_t readyTime = waitCDRomIRQ(); + uint32_t readyTime = waitCDRomIRQ() - ackTime1; uint8_t cause2 = ackCDRomCause(); uint8_t ctrl3 = CDROM_REG0 & ~3; uint8_t response2[16]; @@ -470,7 +470,7 @@ CESTER_TEST(cdlReadN2xwithDMA, test_instances, CDROM_REG0 = 1; uint8_t cause3b = CDROM_REG3_UC; - uint32_t completeTime = waitCDRomIRQ(); + uint32_t completeTime = waitCDRomIRQ() - ackTime2; uint8_t cause4 = ackCDRomCause(); uint8_t ctrl7 = CDROM_REG0 & ~3; uint8_t response4[16]; From 28768b18eb857b36fa93f3856051e865ee64a997 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 27 Dec 2022 10:03:33 -0800 Subject: [PATCH 089/185] Adding runaway read test. --- src/mips/tests/cdrom/cdlreadn.c | 122 ++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c index 04b574764..93631a3cb 100644 --- a/src/mips/tests/cdrom/cdlreadn.c +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -521,3 +521,125 @@ CESTER_TEST(cdlReadN2xwithDMA, test_instances, cester_assert_uint_eq('1', sector[5]); ramsyscall_printf("Basic single full sector readN @2x with DMA at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); ) + +CESTER_TEST(cdlReadN2xRunaway, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + // Mode after reset is undefined technically, + // but seems to be using raw mode. Let's make + // sure it's a known value. + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + uint32_t size = 0; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + while ((CDROM_REG0 & 0x40) == 0); + while (((CDROM_REG0 & 0x40) != 0) && (size < 6)) { + sector[size++] = CDROM_REG2; + } + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime2; + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + CDROM_REG0 = 0; + CDROM_REG3 = 0; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x78, ctrl5); + cester_assert_uint_eq(0x58, ctrl6); + cester_assert_uint_eq(0x78, ctrl7); + cester_assert_uint_eq(0x58, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Switching speed is roughly 650ms for the speed up, + // and then this also contains the seeking time, and + // the time to read the first sector, which is 6.66ms + cester_assert_uint_ge(readyTime, 500000); + // Pausing at 2x is ~35ms + cester_assert_uint_ge(completeTime, 32500); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + cester_assert_uint_eq(6, size); + ramsyscall_printf("Basic single 6 bytes readN @2x at 00:02:16, runaway read, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) From 1b9b57e4a9a53df4d872b7959ae296b8bc870b38 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 27 Dec 2022 23:06:56 -0800 Subject: [PATCH 090/185] Adding a couple more readN tests, and making sure mode is properly reset. --- src/mips/tests/cdrom/cdlreadn.c | 133 ++++++++++++++++++++++++------- src/mips/tests/cdrom/cester-hw.c | 38 ++++----- 2 files changed, 125 insertions(+), 46 deletions(-) diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c index 93631a3cb..9f7158a13 100644 --- a/src/mips/tests/cdrom/cdlreadn.c +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -33,15 +33,6 @@ CESTER_TEST(cdlReadN1x, test_instances, return; } - // Mode after reset is undefined technically, - // but seems to be using raw mode. Let's make - // sure it's a known value. - int setModeDone = setMode(0); - if (!setModeDone) { - cester_assert_true(setModeDone); - return; - } - int setLocDone = setLoc(0, 2, 0x16); if (!setLocDone) { cester_assert_true(setLocDone); @@ -151,15 +142,6 @@ CESTER_TEST(cdlReadN1xwithDMA, test_instances, return; } - // Mode after reset is undefined technically, - // but seems to be using raw mode. Let's make - // sure it's a known value. - int setModeDone = setMode(0); - if (!setModeDone) { - cester_assert_true(setModeDone); - return; - } - int setLocDone = setLoc(0, 2, 0x16); if (!setLocDone) { cester_assert_true(setLocDone); @@ -277,9 +259,6 @@ CESTER_TEST(cdlReadN2x, test_instances, return; } - // Mode after reset is undefined technically, - // but seems to be using raw mode. Let's make - // sure it's a known value. int setModeDone = setMode(0x80); if (!setModeDone) { cester_assert_true(setModeDone); @@ -399,9 +378,6 @@ CESTER_TEST(cdlReadN2xwithDMA, test_instances, return; } - // Mode after reset is undefined technically, - // but seems to be using raw mode. Let's make - // sure it's a known value. int setModeDone = setMode(0x80); if (!setModeDone) { cester_assert_true(setModeDone); @@ -529,9 +505,6 @@ CESTER_TEST(cdlReadN2xRunaway, test_instances, return; } - // Mode after reset is undefined technically, - // but seems to be using raw mode. Let's make - // sure it's a known value. int setModeDone = setMode(0x80); if (!setModeDone) { cester_assert_true(setModeDone); @@ -643,3 +616,109 @@ CESTER_TEST(cdlReadN2xRunaway, test_instances, cester_assert_uint_eq(6, size); ramsyscall_printf("Basic single 6 bytes readN @2x at 00:02:16, runaway read, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); ) + +CESTER_TEST(cdlReadNInAudio, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0x70, 0x21, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t errorTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(4, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + cester_assert_uint_ge(errorTime, 4000000); + ramsyscall_printf("Basic readN in audio track, ack in %ius, errored in %ius\n", ackTime, errorTime); +) + +CESTER_TEST(cdlReadNTooFar, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0x80, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t errorTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(0x10, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + cester_assert_uint_ge(errorTime, 600000); + ramsyscall_printf("Basic readN too far, ack in %ius, errored in %ius\n", ackTime, errorTime); +) diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index f2421ad63..910a9b8bd 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -118,6 +118,24 @@ CESTER_BODY( return cause & 7; } + int setMode(uint8_t mode) { + uint32_t imask = IMASK; + uint8_t cause; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = mode; + CDROM_REG1 = CDL_SETMODE; + waitCDRomIRQ(); + cause = ackCDRomCause(); + CDROM_REG1; + if (cause != 3) return 0; + + IMASK = imask; + return 1; + } + static inline int resetCDRom() { uint32_t imask = IMASK; uint8_t cause; @@ -143,7 +161,7 @@ CESTER_BODY( // wait 10ms for things to settle while (updateTime() < 10000); IMASK = imask; - return 1; + return setMode(0); } static int setLoc(uint8_t minute, uint8_t second, uint8_t frame) { @@ -228,24 +246,6 @@ CESTER_BODY( return 1; } - int setMode(uint8_t mode) { - uint32_t imask = IMASK; - uint8_t cause; - - IMASK = imask | IRQ_CDROM; - - CDROM_REG0 = 0; - CDROM_REG2 = mode; - CDROM_REG1 = CDL_SETMODE; - waitCDRomIRQ(); - cause = ackCDRomCause(); - CDROM_REG1; - if (cause != 3) return 0; - - IMASK = imask; - return 1; - } - uint8_t getCtrl() { uint32_t imask = IMASK; uint8_t cause; From f1d387873137522ff94ac2019c47cf4c4443de94 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 15:40:11 -0800 Subject: [PATCH 091/185] Simplifying / refactoring a bit, and derping reads for now. --- src/core/cdrom.cc | 478 ++++++++++++++++++++++++++++------------------ src/core/cdrom.h | 8 +- 2 files changed, 297 insertions(+), 189 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index c478c7065..2a354173a 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -103,6 +103,10 @@ class CDRomImpl final : public PCSX::CDRom { m_gotAck = false; m_waitingAck = false; m_speed = Speed::Simple; + m_speedChanged = false; + m_status = Status::IDLE; + m_readDelayed = 0; + m_dataRequested = false; } void interrupt() override { @@ -117,12 +121,55 @@ class CDRomImpl final : public PCSX::CDRom { return; } auto handler = c_commandsHandlers[m_command]; - (this->*handler)(); + if (handler) { + (this->*handler)(); + } else { + setResponse(getStatus() | 1); + appendResponse(0x40); + m_cause = Cause::Error; + m_paramFIFOSize = 0; + m_state = 0; + m_command = 0; + triggerIRQ(); + } } - void readInterrupt() override {} + void readInterrupt() override { + static const std::chrono::nanoseconds c_retryDelay = 50us; + if ((m_status == Status::IDLE) || (m_status == Status::SEEKING)) { + m_readDelayed = 0; + return; + } + if (m_command != 0) { + m_readDelayed++; + scheduleRead(c_retryDelay); + return; + } + switch (m_status) { + case Status::READING_DATA: { + auto readDelay = computeReadDelay(); + readDelay -= m_readDelayed * c_retryDelay; + m_readDelayed = 0; + m_cause = Cause::DataReady; + m_dataFIFOIndex = 0; + m_dataFIFOPending = 2048; + if (m_dataRequested) m_dataFIFOSize = 2048; + triggerIRQ(); + scheduleRead(readDelay); + } break; + default: + PCSX::g_system->log(PCSX::LogClass::CDROM, "unsupported yet\n"); + PCSX::g_system->pause(); + break; + } + } - void dmaInterrupt() override {} + void dmaInterrupt() override { + if (HW_DMA3_CHCR & SWAP_LE32(0x01000000)) { + HW_DMA3_CHCR &= SWAP_LE32(~0x01000000); + DMA_INTERRUPT<3>(); + } + } void schedule(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDR, cycles); } void schedule(std::chrono::nanoseconds delay) { schedule(PCSX::psxRegisters::durationToCycles(delay)); } @@ -300,6 +347,17 @@ class CDRomImpl final : public PCSX::CDRom { switch (m_registerIndex) { case 0: { // ?? + if (value == 0) { + m_dataRequested = false; + m_dataFIFOSize = 0; + m_dataFIFOIndex = 0; + return; + } + if (value == 0x80) { + m_dataRequested = true; + m_dataFIFOSize = m_dataFIFOPending; + return; + } PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:0 not available yet\n"); PCSX::g_system->pause(); } break; @@ -325,12 +383,10 @@ class CDRomImpl final : public PCSX::CDRom { if (value & 0x10) { // request ack? // TODO: act on this? - return; } if (value & 0x08) { // ?? // TODO: act on this? - return; } PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:1 not available yet\n"); PCSX::g_system->pause(); @@ -349,11 +405,29 @@ class CDRomImpl final : public PCSX::CDRom { } void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: DMA not available yet\n"); - PCSX::g_system->pause(); + uint32_t size = bcr >> 16; + size *= bcr & 0xffff; + size *= 4; + if (size == 0) size = 0xffffffff; + size = std::min(m_dataFIFOSize - m_dataFIFOIndex, size); + auto ptr = (uint8_t *)PSXM(madr); + for (auto i = 0; i < size; i++) { + *ptr++ = m_dataFIFO[m_dataFIFOIndex++]; + } + PCSX::g_emulator->m_cpu->Clear(madr, size / 4); + if (PCSX::g_emulator->settings.get() + .get()) { + PCSX::g_emulator->m_debug->checkDMAwrite(3, madr, size); + } + if (chcr == 0x11400100) { + scheduleDMA(size / 16); + } else { + scheduleDMA(size / 4); + } } void startCommand(uint8_t command) { + m_state = 0; m_command = command; if (PCSX::g_emulator->settings.get() .get()) { @@ -376,7 +450,20 @@ class CDRomImpl final : public PCSX::CDRom { } auto handler = c_commandsHandlers[command]; - (this->*handler)(); + + std::chrono::nanoseconds initialDelay = c_commandsInitialDelay[command]; + + if (handler == nullptr) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command %i\n", m_command); + if (PCSX::g_emulator->settings.get() + .get()) { + PCSX::g_system->pause(); + } + initialDelay = 750us; + } + + m_state = 1; + schedule(initialDelay); } enum class SeekType { DATA, CDDA }; @@ -398,78 +485,136 @@ class CDRomImpl final : public PCSX::CDRom { return std::chrono::microseconds(distance * 3) + 150ms; } + std::chrono::nanoseconds computeReadDelay() { return m_speed == Speed::Simple ? 13333us : 6666us; } + // Command 1. void cdlNop() { + setResponse(getStatus(true)); + m_cause = Cause::Acknowledge; + m_command = 0; + triggerIRQ(); + } + + // Command 2. + void cdlSetLoc() { + // TODO: probably should error out if no disc or + // lid open? + // What happens when issued during Read / Play? + auto maybeMSF = getMSF(m_paramFIFO); + if (maybeMSF.has_value()) { + setResponse(getStatus()); + m_cause = Cause::Acknowledge; + m_seekPosition = maybeMSF.value(); + } else { + setResponse(getStatus() | 1); + appendResponse(0x10); + m_cause = Cause::Error; + } + m_paramFIFOSize = 0; + m_command = 0; + triggerIRQ(); + } + + // Command 6. + void cdlReadN() { switch (m_state) { - case 0: - m_state = 1; - schedule(750us); - break; case 1: { - setResponse(getStatus(true)); + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; + } + schedule(seekDelay); m_cause = Cause::Acknowledge; - m_paramFIFOSize = 0; - m_state = 0; - m_command = 0; + m_state = 2; + setResponse(getStatus()); + m_status = Status::SEEKING; triggerIRQ(); } break; + case 2: + m_status = Status::IDLE; + if (!m_gotAck) { + m_waitingAck = true; + m_state = 3; + break; + } + [[fallthrough]]; + case 3: { + m_currentPosition = m_seekPosition; + unsigned track = m_iso->getTrack(m_seekPosition); + if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(4); + triggerIRQ(); + } else if (track == 0) { + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(0x10); + triggerIRQ(); + } else { + m_status = Status::READING_DATA; + scheduleRead(computeReadDelay()); + } + m_command = 0; + } break; } } - // Command 2. - void cdlSetLoc() { + // Command 9. + void cdlPause() { switch (m_state) { - case 0: - m_state = 1; - schedule(1ms); - break; case 1: { - // TODO: probably should error out if no disc or - // lid open? - // What happens when issued during Read / Play? - auto maybeMSF = getMSF(m_paramFIFO); - if (maybeMSF.has_value()) { - setResponse(getStatus()); - m_cause = Cause::Acknowledge; - m_seekPosition = maybeMSF.value(); + if (m_status == Status::IDLE) { + schedule(200us); } else { - setResponse(getStatus() | 1); - appendResponse(0x10); - m_cause = Cause::Error; + schedule(m_speed == Speed::Simple ? 70ms : 35ms); } - m_paramFIFOSize = 0; - m_state = 0; - m_command = 0; + m_cause = Cause::Acknowledge; + m_state = 2; + m_status = Status::IDLE; + setResponse(getStatus()); triggerIRQ(); } break; + case 2: + if (!m_gotAck) { + m_waitingAck = true; + m_state = 3; + break; + } + [[fallthrough]]; + case 3: + m_cause = Cause::Complete; + m_command = 0; + setResponse(getStatus()); + triggerIRQ(); + break; } } // Command 10. void cdlInit() { switch (m_state) { - case 0: + case 1: + m_cause = Cause::Acknowledge; + m_state = 2; + setResponse(getStatus()); + triggerIRQ(); + schedule(120ms); + break; + case 2: // TODO: figure out exactly the various states of the CD-Rom controller // that are being reset, and their value. - m_state = 1; m_motorOn = true; + m_speedChanged = false; m_currentPosition.reset(); m_currentPosition.s = 2; m_seekPosition.reset(); m_seekPosition.s = 2; m_invalidLocL = false; m_speed = Speed::Simple; + m_status = Status::IDLE; memset(m_lastLocP, 0, sizeof(m_lastLocP)); - schedule(2ms); - break; - case 1: - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - triggerIRQ(); - schedule(120ms); - break; - case 2: if (!m_gotAck) { m_waitingAck = true; m_state = 3; @@ -478,7 +623,6 @@ class CDRomImpl final : public PCSX::CDRom { [[fallthrough]]; case 3: m_cause = Cause::Complete; - m_state = 0; m_command = 0; setResponse(getStatus()); triggerIRQ(); @@ -488,136 +632,108 @@ class CDRomImpl final : public PCSX::CDRom { // Command 14 void cdlSetMode() { - switch (m_state) { - case 0: - m_state = 1; - schedule(750us); - break; - case 1: { - uint8_t mode = m_paramFIFO[0]; - // TODO: add the rest of the mode bits. - m_speed = mode & 0x80 ? Speed::Double : Speed::Simple; - setResponse(getStatus()); - m_cause = Cause::Acknowledge; - m_paramFIFOSize = 0; - m_state = 0; - m_command = 0; - triggerIRQ(); - } break; + uint8_t mode = m_paramFIFO[0]; + // TODO: add the rest of the mode bits. + if (mode & 0x80) { + if (m_speed == Speed::Simple) { + m_speed = Speed::Double; + m_speedChanged = true; + } + } else { + if (m_speed == Speed::Double) { + m_speed = Speed::Simple; + m_speedChanged = true; + } } + if (mode & 0x7f) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode:\n", mode); + PCSX::g_system->pause(); + } + setResponse(getStatus()); + m_cause = Cause::Acknowledge; + m_paramFIFOSize = 0; + m_command = 0; + triggerIRQ(); } // Command 16. void cdlGetLocL() { - switch (m_state) { - case 0: - m_state = 1; - schedule(750us); - break; - case 1: { - // TODO: probably should error out if no disc or - // lid open? - if (m_invalidLocL) { - setResponse(getStatus() | 1); - appendResponse(0x80); - m_cause = Cause::Error; - } else { - setResponse(std::string_view((char *)m_lastLocL, sizeof(m_lastLocL))); - m_cause = Cause::Acknowledge; - } - m_state = 0; - m_command = 0; - triggerIRQ(); - } break; + // TODO: probably should error out if no disc or + // lid open? + if (m_invalidLocL) { + setResponse(getStatus() | 1); + appendResponse(0x80); + m_cause = Cause::Error; + } else { + setResponse(std::string_view((char *)m_lastLocL, sizeof(m_lastLocL))); + m_cause = Cause::Acknowledge; } + m_command = 0; + triggerIRQ(); } // Command 17. void cdlGetLocP() { - switch (m_state) { - case 0: - m_state = 1; - schedule(750us); - break; - case 1: { - // TODO: probably should error out if no disc or - // lid open? - m_iso->getLocP(m_currentPosition, m_lastLocP); - setResponse(std::string_view((char *)m_lastLocP, sizeof(m_lastLocP))); - m_cause = Cause::Acknowledge; - m_state = 0; - m_command = 0; - triggerIRQ(); - } break; - } + // TODO: probably should error out if no disc or + // lid open? + m_iso->getLocP(m_currentPosition, m_lastLocP); + setResponse(std::string_view((char *)m_lastLocP, sizeof(m_lastLocP))); + m_cause = Cause::Acknowledge; + m_command = 0; + triggerIRQ(); } // Command 19. void cdlGetTN() { - switch (m_state) { - case 0: - m_state = 1; - schedule(2ms); - break; - case 1: { - // TODO: probably should error out if no disc or - // lid open? - setResponse(getStatus()); - appendResponse(1); - appendResponse(PCSX::IEC60908b::itob(m_iso->getTN())); - m_cause = Cause::Acknowledge; - m_state = 0; - m_command = 0; - triggerIRQ(); - } break; - } + // TODO: probably should error out if no disc or + // lid open? + setResponse(getStatus()); + appendResponse(1); + appendResponse(PCSX::IEC60908b::itob(m_iso->getTN())); + m_cause = Cause::Acknowledge; + m_command = 0; + triggerIRQ(); } // Command 20. void cdlGetTD() { - switch (m_state) { - case 0: - m_state = 1; - schedule(750us); - break; - case 1: { - // TODO: probably should error out if no disc or - // lid open? - auto track = PCSX::IEC60908b::btoi(m_paramFIFO[0]); - if (!isValidBCD(m_paramFIFO[0]) || (track > m_iso->getTN())) { - setResponse(getStatus() | 1); - appendResponse(0x10); - m_cause = Cause::Error; - } else { - setResponse(getStatus()); - auto td = m_iso->getTD(track); - appendResponse(PCSX::IEC60908b::itob(td.m)); - appendResponse(PCSX::IEC60908b::itob(td.s)); - m_cause = Cause::Acknowledge; - } - m_paramFIFOSize = 0; - m_state = 0; - m_command = 0; - triggerIRQ(); - } break; + // TODO: probably should error out if no disc or + // lid open? + auto track = PCSX::IEC60908b::btoi(m_paramFIFO[0]); + if (!isValidBCD(m_paramFIFO[0]) || (track > m_iso->getTN())) { + setResponse(getStatus() | 1); + appendResponse(0x10); + m_cause = Cause::Error; + } else { + setResponse(getStatus()); + auto td = m_iso->getTD(track); + appendResponse(PCSX::IEC60908b::itob(td.m)); + appendResponse(PCSX::IEC60908b::itob(td.s)); + m_cause = Cause::Acknowledge; } + m_paramFIFOSize = 0; + m_command = 0; + triggerIRQ(); } // Command 21. void cdlSeekL() { switch (m_state) { - case 0: - m_state = 1; - schedule(1ms); - break; case 1: m_cause = Cause::Acknowledge; m_state = 2; setResponse(getStatus()); triggerIRQ(); - schedule(computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA)); + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; + } + m_status = Status::SEEKING; + schedule(seekDelay); break; case 2: + m_status = Status::IDLE; if (!m_gotAck) { m_waitingAck = true; m_state = 3; @@ -625,7 +741,6 @@ class CDRomImpl final : public PCSX::CDRom { } [[fallthrough]]; case 3: { - // TODO: read sector and cache sector header for locL m_currentPosition = m_seekPosition; unsigned track = m_iso->getTrack(m_seekPosition); if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { @@ -641,7 +756,6 @@ class CDRomImpl final : public PCSX::CDRom { setResponse(getStatus()); } m_invalidLocL = true; - m_state = 0; m_command = 0; triggerIRQ(); } break; @@ -651,18 +765,21 @@ class CDRomImpl final : public PCSX::CDRom { // Command 22. void cdlSeekP() { switch (m_state) { - case 0: - m_state = 1; - schedule(1ms); - break; case 1: m_cause = Cause::Acknowledge; m_state = 2; setResponse(getStatus()); triggerIRQ(); - schedule(computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::CDDA)); + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::CDDA); + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; + } + m_status = Status::SEEKING; + schedule(seekDelay); break; case 2: + m_status = Status::IDLE; if (!m_gotAck) { m_waitingAck = true; m_state = 3; @@ -681,36 +798,12 @@ class CDRomImpl final : public PCSX::CDRom { setResponse(getStatus()); } m_invalidLocL = true; - m_state = 0; m_command = 0; triggerIRQ(); } break; } } - void cdlUnk() { - switch (m_state) { - case 0: - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command %i\n", m_command); - if (PCSX::g_emulator->settings.get() - .get()) { - PCSX::g_system->pause(); - } - m_state = 1; - schedule(750us); - break; - case 1: - setResponse(getStatus() | 1); - appendResponse(0x40); - m_cause = Cause::Error; - m_paramFIFOSize = 0; - m_state = 0; - m_command = 0; - triggerIRQ(); - break; - } - } - typedef void (CDRomImpl::*CommandType)(); const CommandType c_commandsHandlers[31] { @@ -724,14 +817,14 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 &CDRomImpl::cdlReset, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 #else - &CDRomImpl::cdlUnk, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, &CDRomImpl::cdlUnk, // 0 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 4 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlInit, &CDRomImpl::cdlUnk, // 8 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlSetMode, &CDRomImpl::cdlUnk, // 12 - &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, &CDRomImpl::cdlUnk, &CDRomImpl::cdlGetTN, // 16 - &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, &CDRomImpl::cdlUnk, // 20 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 24 - &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, &CDRomImpl::cdlUnk, // 28 + nullptr, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, nullptr, // 0 + nullptr, nullptr, &CDRomImpl::cdlReadN, nullptr, // 4 + nullptr, &CDRomImpl::cdlPause, &CDRomImpl::cdlInit, nullptr, // 8 + nullptr, nullptr, &CDRomImpl::cdlSetMode, nullptr, // 12 + &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, nullptr, &CDRomImpl::cdlGetTN, // 16 + &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, nullptr, // 20 + nullptr, nullptr, nullptr, nullptr, // 24 + nullptr, nullptr, nullptr, // 28 #endif }; @@ -746,6 +839,17 @@ class CDRomImpl final : public PCSX::CDRom { 0, 0, 0, // 28 }; + static constexpr std::chrono::nanoseconds c_commandsInitialDelay[31] = { + 0ns, 750us, 1ms, 0ns, // 0 + 0ns, 0ns, 1ms, 0ns, // 4 + 0ns, 1ms, 2ms, 0ns, // 8 + 0ns, 0ns, 750us, 0ns, // 12 + 750us, 750us, 0ns, 2ms, // 16 + 750us, 1ms, 1ms, 0ns, // 20 + 0ns, 0ns, 0ns, 0ns, // 24 + 0ns, 0ns, 0ns, // 28 + }; + void logCDROM(uint8_t command) { uint32_t pc = PCSX::g_emulator->m_cpu->m_regs.pc; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index a05b7d3a3..3e40eaae3 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -117,6 +117,7 @@ class CDRom { uint8_t m_responseFIFO[16] = {0}; uint32_t m_dataFIFOIndex = 0; uint32_t m_dataFIFOSize = 0; + uint32_t m_dataFIFOPending = 0; uint8_t m_paramFIFOSize = 0; uint8_t m_responseFIFOIndex = 0; uint8_t m_responseFIFOSize = 0; @@ -126,14 +127,16 @@ class CDRom { bool m_gotAck = false; bool m_waitingAck = false; bool m_motorOn = false; + bool m_speedChanged = false; bool m_invalidLocL = false; + bool m_dataRequested = false; enum class Status { - STOPPED, + IDLE, READING_DATA, SEEKING, PLAYING_CDDA, }; - Status m_status = Status::STOPPED; + Status m_status = Status::IDLE; uint8_t m_state = 0; uint8_t m_command = 0; @@ -152,6 +155,7 @@ class CDRom { uint8_t m_lastLocP[8] = {0}; uint8_t m_lastLocL[8] = {0}; enum class Speed { Simple, Double } m_speed; + unsigned m_readDelayed = 0; private: friend class Widgets::IsoBrowser; From a553382ec77877f4bfa24ad4f750349567a07098 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 16:21:43 -0800 Subject: [PATCH 092/185] Actually sending data. --- src/core/cdrom.cc | 38 +++++++++++++++++++++++++++++++++++++- src/core/cdrom.h | 1 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 2a354173a..bd25a8566 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -147,6 +147,27 @@ class CDRomImpl final : public PCSX::CDRom { } switch (m_status) { case Status::READING_DATA: { + m_iso->readTrack(m_currentPosition); + auto buffer = m_iso->getBuffer(); + uint32_t size = 0; + switch (m_readSpan) { + case ReadSpan::S2048: + size = 2048; + if (buffer[3] == 1) { + memcpy(m_dataFIFO, buffer + 4, 2048); + } else { + memcpy(m_dataFIFO, buffer + 12, 2048); + } + break; + case ReadSpan::S2328: + size = 2328; + memcpy(m_dataFIFO, buffer + 12, 2328); + break; + case ReadSpan::S2340: + size = 2340; + memcpy(m_dataFIFO, buffer + 4, 2340); + break; + } auto readDelay = computeReadDelay(); readDelay -= m_readDelayed * c_retryDelay; m_readDelayed = 0; @@ -645,7 +666,22 @@ class CDRomImpl final : public PCSX::CDRom { m_speedChanged = true; } } - if (mode & 0x7f) { + switch ((mode & 0x30) >> 4) { + case 0: + m_readSpan = ReadSpan::S2048; + break; + case 1: + m_readSpan = ReadSpan::S2328; + break; + case 2: + m_readSpan = ReadSpan::S2340; + break; + case 3: + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode:\n", mode); + PCSX::g_system->pause(); + break; + } + if (mode & 0x4f) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode:\n", mode); PCSX::g_system->pause(); } diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 3e40eaae3..7357c2976 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -155,6 +155,7 @@ class CDRom { uint8_t m_lastLocP[8] = {0}; uint8_t m_lastLocL[8] = {0}; enum class Speed { Simple, Double } m_speed; + enum class ReadSpan { S2048, S2328, S2340 } m_readSpan; unsigned m_readDelayed = 0; private: From 14cc01599a541dbca2d211ca06f89954708b3ce5 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 17:03:34 -0800 Subject: [PATCH 093/185] Tests passing. --- src/core/cdrom.cc | 3 ++- src/core/cdrom.h | 12 +++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index bd25a8566..ed6250b99 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -175,6 +175,7 @@ class CDRomImpl final : public PCSX::CDRom { m_dataFIFOIndex = 0; m_dataFIFOPending = 2048; if (m_dataRequested) m_dataFIFOSize = 2048; + setResponse(getStatus()); triggerIRQ(); scheduleRead(readDelay); } break; @@ -593,11 +594,11 @@ class CDRomImpl final : public PCSX::CDRom { } m_cause = Cause::Acknowledge; m_state = 2; - m_status = Status::IDLE; setResponse(getStatus()); triggerIRQ(); } break; case 2: + m_status = Status::IDLE; if (!m_gotAck) { m_waitingAck = true; m_state = 3; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 7357c2976..e0613c544 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -130,15 +130,16 @@ class CDRom { bool m_speedChanged = false; bool m_invalidLocL = false; bool m_dataRequested = false; - enum class Status { + enum class Status : uint8_t { IDLE, READING_DATA, SEEKING, PLAYING_CDDA, - }; - Status m_status = Status::IDLE; + } m_status = Status::IDLE; uint8_t m_state = 0; uint8_t m_command = 0; + enum class Speed : uint8_t { Simple, Double } m_speed; + enum class ReadSpan : uint8_t { S2048, S2328, S2340 } m_readSpan; enum class Cause : uint8_t { None = 0, @@ -147,15 +148,12 @@ class CDRom { Acknowledge = 3, End = 4, Error = 5, - }; - Cause m_cause = Cause::None; + } m_cause = Cause::None; MSF m_currentPosition; MSF m_seekPosition; uint8_t m_lastLocP[8] = {0}; uint8_t m_lastLocL[8] = {0}; - enum class Speed { Simple, Double } m_speed; - enum class ReadSpan { S2048, S2328, S2340 } m_readSpan; unsigned m_readDelayed = 0; private: From 1f6e8a8197ff965d5e7f3a7a69c3b8cf90b32d79 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 17:13:10 -0800 Subject: [PATCH 094/185] Proper clamping on start position. --- src/mips/tests/cdrom/cdlgetlocp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgetlocp.c b/src/mips/tests/cdrom/cdlgetlocp.c index 8d3bf7eb9..21d2d3419 100644 --- a/src/mips/tests/cdrom/cdlgetlocp.c +++ b/src/mips/tests/cdrom/cdlgetlocp.c @@ -256,7 +256,7 @@ CESTER_TEST(cdlGetLocPinT5, test_instances, start = absolute - relative; } cester_assert_uint_eq(5, response.track); - cester_assert_uint_ge(start, 316500); + cester_assert_uint_eq(316500, start); cester_assert_uint_eq(0, inPregap); cester_assert_uint_eq(1, response.index); cester_assert_uint_ge(absolute, 316535); @@ -316,7 +316,7 @@ CESTER_TEST(cdlGetLocPinT5Pregap, test_instances, start = absolute - relative; } cester_assert_uint_eq(5, response.track); - cester_assert_uint_ge(start, 316500); + cester_assert_uint_eq(316500, start); cester_assert_uint_eq(1, inPregap); cester_assert_uint_eq(0, response.index); cester_assert_uint_ge(absolute, 316460); From 9431018b50b9909121e6d79d11274851bc82e23b Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 19:11:46 -0800 Subject: [PATCH 095/185] Adding cdlTest test. --- src/mips/tests/cdrom/cdltest.c | 161 +++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdrom.c | 1 + 2 files changed, 162 insertions(+) create mode 100644 src/mips/tests/cdrom/cdltest.c diff --git a/src/mips/tests/cdrom/cdltest.c b/src/mips/tests/cdrom/cdltest.c new file mode 100644 index 000000000..7cf0299db --- /dev/null +++ b/src/mips/tests/cdrom/cdltest.c @@ -0,0 +1,161 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlTestNoArg, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_TEST; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("Basic cdlTest with no args, errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlTest20, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = 0x20; + CDROM_REG1 = CDL_TEST; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(4, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic cdlTest with arg = 0x20, ack in %ius, response = %02x %02x %02x %02x\n", ackTime, response1[0], response1[1], response1[2], response1[3]); + + IMASK = imask; +) + +CESTER_TEST(cdlTest20ExtraArgs, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = 0x20; + CDROM_REG2 = 0x00; + CDROM_REG1 = CDL_TEST; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("Basic cdlTest with arg = 0x20, 0x00, errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlTestff, test_instance, + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = 0xff; + CDROM_REG1 = CDL_TEST; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x10, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic cdlTest with arg = 0xff, errored in %ius\n", ackTime); + + IMASK = imask; +) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index c74180704..a1f18510a 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -48,4 +48,5 @@ SOFTWARE. #include "cdlseekp.c" #include "cdlsetloc.c" #include "cdlsetmode.c" +#include "cdltest.c" #include "invalid.c" From 272a844a57e50840c006a8391c5fcf02ab432748 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 19:12:12 -0800 Subject: [PATCH 096/185] Supporting param fifo flush. --- src/core/cdrom.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index ed6250b99..fd798de4b 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -410,7 +410,11 @@ class CDRomImpl final : public PCSX::CDRom { // ?? // TODO: act on this? } - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:1 not available yet\n"); + if (value & 0x40) { + m_paramFIFOSize = 0; + return; + } + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:1(%02x) not available yet\n", value); PCSX::g_system->pause(); } break; case 2: { From 876d3544b9ba822ff0b59de79e9d3c8d4c3edbf8 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 20:20:42 -0800 Subject: [PATCH 097/185] Fixing cdlTest test. --- src/mips/tests/cdrom/cdltest.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/mips/tests/cdrom/cdltest.c b/src/mips/tests/cdrom/cdltest.c index 7cf0299db..868a00170 100644 --- a/src/mips/tests/cdrom/cdltest.c +++ b/src/mips/tests/cdrom/cdltest.c @@ -27,6 +27,12 @@ SOFTWARE. // clang-format off CESTER_TEST(cdlTestNoArg, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + initializeTime(); uint32_t imask = IMASK; @@ -60,6 +66,12 @@ CESTER_TEST(cdlTestNoArg, test_instance, ) CESTER_TEST(cdlTest20, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + initializeTime(); uint32_t imask = IMASK; @@ -92,6 +104,12 @@ CESTER_TEST(cdlTest20, test_instance, ) CESTER_TEST(cdlTest20ExtraArgs, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + initializeTime(); uint32_t imask = IMASK; @@ -127,6 +145,12 @@ CESTER_TEST(cdlTest20ExtraArgs, test_instance, ) CESTER_TEST(cdlTestff, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + initializeTime(); uint32_t imask = IMASK; From c478e69ad09ba31c8a82fe3b1613ad8bc93eb152 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 20:21:03 -0800 Subject: [PATCH 098/185] Adding id test. --- src/mips/tests/cdrom/cdlid.c | 126 +++++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdrom.c | 1 + 2 files changed, 127 insertions(+) create mode 100644 src/mips/tests/cdrom/cdlid.c diff --git a/src/mips/tests/cdrom/cdlid.c b/src/mips/tests/cdrom/cdlid.c new file mode 100644 index 000000000..9d4ce0e7b --- /dev/null +++ b/src/mips/tests/cdrom/cdlid.c @@ -0,0 +1,126 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlId, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETID; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(8, responseSize2); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic cdlId, ack in %ius, complete in %ius\n", ackTime, completeTime); + ramsyscall_printf("Full response: %02x %02x %02x %02x %02x %02x %02x %02x\n", + response2[0], response2[1], response2[2], response2[3], + response2[4], response2[5], response2[6], response2[7]); + + IMASK = imask; +) + +CESTER_TEST(cdlIdTooManyArgs, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_GETID; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("Basic cdlId with too many args, errored in %ius\n", errorTime); + + IMASK = imask; +) + diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index a1f18510a..5b7f31b0a 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -42,6 +42,7 @@ SOFTWARE. #include "cdlgetlocp.c" #include "cdlgettd.c" #include "cdlgettn.c" +#include "cdlid.c" #include "cdlinit.c" #include "cdlreadn.c" #include "cdlseekl.c" From 4d4535eaaca254dd670312870ebd0b6dcd1c38a4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 20:52:20 -0800 Subject: [PATCH 099/185] Getting somewhere. --- src/core/cdrom.cc | 75 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 7 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index fd798de4b..de3a0674d 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -288,10 +288,8 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t read3() override { switch (m_registerIndex & 1) { case 0: { - // cause mask - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: r3:0 not available yet\n"); - PCSX::g_system->pause(); - return 0; + // cause mask? this doesn't make sense. + return 0x1f; // derp? } break; case 1: { // cause @@ -380,7 +378,7 @@ class CDRomImpl final : public PCSX::CDRom { m_dataFIFOSize = m_dataFIFOPending; return; } - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:0 not available yet\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:0(%02x) not available yet\n", value); PCSX::g_system->pause(); } break; case 1: { @@ -845,6 +843,69 @@ class CDRomImpl final : public PCSX::CDRom { } } + // Command 25. + void cdlTest() { + static constexpr uint8_t c_test20[] = {0x94, 0x09, 0x19, 0xc0}; + if (m_paramFIFOSize == 0) { + m_cause = Cause::Error; + m_paramFIFOSize = 0; + m_command = 0; + setResponse(getStatus() | 1); + appendResponse(0x20); + triggerIRQ(); + return; + } + + switch (m_paramFIFO[0]) { + case 0x20: + if (m_paramFIFOSize == 1) { + setResponse(std::string_view((const char *)c_test20, sizeof(c_test20))); + m_cause = Cause::Acknowledge; + } else { + setResponse(getStatus() | 1); + appendResponse(0x20); + m_cause = Cause::Error; + } + break; + default: + setResponse(getStatus() | 1); + appendResponse(0x10); + m_cause = Cause::Error; + break; + } + m_paramFIFOSize = 0; + m_command = 0; + triggerIRQ(); + } + + // Command 26. + void cdlID() { + switch (m_state) { + case 1: + m_cause = Cause::Acknowledge; + m_state = 2; + setResponse(getStatus()); + triggerIRQ(); + schedule(5ms); + break; + case 2: + if (!m_gotAck) { + m_waitingAck = true; + m_state = 3; + break; + } + [[fallthrough]]; + case 3: { + // Adjust this response for various types of discs and situations. + m_cause = Cause::Complete; + setResponse(getStatus()); + appendResponse("\x00\x20\x00PCSX"); + m_command = 0; + triggerIRQ(); + } break; + } + } + typedef void (CDRomImpl::*CommandType)(); const CommandType c_commandsHandlers[31] { @@ -864,7 +925,7 @@ class CDRomImpl final : public PCSX::CDRom { nullptr, nullptr, &CDRomImpl::cdlSetMode, nullptr, // 12 &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, nullptr, &CDRomImpl::cdlGetTN, // 16 &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, nullptr, // 20 - nullptr, nullptr, nullptr, nullptr, // 24 + nullptr, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, nullptr, // 24 nullptr, nullptr, nullptr, // 28 #endif }; @@ -887,7 +948,7 @@ class CDRomImpl final : public PCSX::CDRom { 0ns, 0ns, 750us, 0ns, // 12 750us, 750us, 0ns, 2ms, // 16 750us, 1ms, 1ms, 0ns, // 20 - 0ns, 0ns, 0ns, 0ns, // 24 + 0ns, 750us, 5ms, 0ns, // 24 0ns, 0ns, 0ns, // 28 }; From 0fe3ef86e3057beed8e94eca7306b139f5ac8128 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 21:05:11 -0800 Subject: [PATCH 100/185] Derp. --- src/core/cdrom.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index de3a0674d..6c56b2995 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -175,6 +175,7 @@ class CDRomImpl final : public PCSX::CDRom { m_dataFIFOIndex = 0; m_dataFIFOPending = 2048; if (m_dataRequested) m_dataFIFOSize = 2048; + m_currentPosition++; setResponse(getStatus()); triggerIRQ(); scheduleRead(readDelay); From ffdcc5e82e8fecf7835f9f3787e6eb3667b03acb Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 21:28:18 -0800 Subject: [PATCH 101/185] Slowing down ROM access. --- src/core/DynaRec_aa64/recompiler.cc | 10 ++++++---- src/core/DynaRec_x64/recompiler.cc | 7 +++++-- src/core/DynaRec_x86/iR3000A.cc | 4 +++- src/core/psxemulator.h | 3 ++- src/core/psxinterpreter.cc | 3 ++- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/core/DynaRec_aa64/recompiler.cc b/src/core/DynaRec_aa64/recompiler.cc index 33171fef7..335f6b9b7 100644 --- a/src/core/DynaRec_aa64/recompiler.cc +++ b/src/core/DynaRec_aa64/recompiler.cc @@ -245,7 +245,8 @@ DynarecCallback DynaRecCPU::recompile(DynarecCallback* callback, uint32_t pc, bo m_pc = pc & ~3; const auto startingPC = m_pc; - int count = 0; // How many instructions have we compiled? + unsigned count = 0; // How many instructions have we compiled? + unsigned extra = 0; // How many instructions from rom? #if defined(__APPLE__) gen.setRW(); // Mark code cache as readable/writeable before emitting code @@ -288,6 +289,7 @@ DynarecCallback DynaRecCPU::recompile(DynarecCallback* callback, uint32_t pc, bo m_regs.code = *p; // Actually read the instruction m_pc += 4; // Increment recompiler PC count++; // Increment instruction count + if ((m_pc & 0xffc00000) == 0xbfc00000) extra++; const auto func = m_recBSC[m_regs.code >> 26]; // Look up the opcode in our decoding LUT (*this.*func)(); // Jump into the handler to recompile it @@ -304,9 +306,9 @@ DynarecCallback DynaRecCPU::recompile(DynarecCallback* callback, uint32_t pc, bo m_linkedPC = std::nullopt; } - gen.Ldr(w0, MemOperand(contextPointer, CYCLE_OFFSET)); // Fetch cycle count from memory - gen.Add(w0, w0, count * PCSX::Emulator::BIAS); // Add block cycles - gen.Str(w0, MemOperand(contextPointer, CYCLE_OFFSET)); // Store cycles back to memory + gen.Ldr(w0, MemOperand(contextPointer, CYCLE_OFFSET)); // Fetch cycle count from memory + gen.Add(w0, w0, (count + extra * PCSX::Emulator::ROM_EXTRA_BIAS) * PCSX::Emulator::BIAS); // Add block cycles + gen.Str(w0, MemOperand(contextPointer, CYCLE_OFFSET)); // Store cycles back to memory // Link block else return to dispatcher if (m_linkedPC && ENABLE_BLOCK_LINKING && m_linkedPC.value() != startingPC) { diff --git a/src/core/DynaRec_x64/recompiler.cc b/src/core/DynaRec_x64/recompiler.cc index 4510039bc..50248f7f5 100644 --- a/src/core/DynaRec_x64/recompiler.cc +++ b/src/core/DynaRec_x64/recompiler.cc @@ -329,7 +329,8 @@ DynarecCallback DynaRecCPU::recompile(uint32_t pc, bool fullLoadDelayEmulation, if (!isPcValid(m_pc)) return m_invalidBlock; const auto startingPC = m_pc; - int count = 0; // How many instructions have we compiled? + unsigned count = 0; // How many instructions have we compiled? + unsigned extra = 0; // How many instructions in rom? DynarecCallback* callback = getBlockPointer(m_pc); // Pointer to where we'll store the addr of the emitted code if (align) { @@ -399,6 +400,7 @@ DynarecCallback DynaRecCPU::recompile(uint32_t pc, bool fullLoadDelayEmulation, m_regs.code = *(uint32_t*)PSXM(m_pc); m_pc += 4; // Increment recompiler PC count++; // Increment instruction count + if ((m_pc & 0xffc00000) == 0xbfc00000) extra++; const auto func = m_recBSC[m_regs.code >> 26]; // Look up the opcode in our decoding LUT (*this.*func)(); // Jump into the handler to recompile it @@ -446,7 +448,8 @@ DynarecCallback DynaRecCPU::recompile(uint32_t pc, bool fullLoadDelayEmulation, endProfiling(); } - gen.add(dword[contextPointer + CYCLE_OFFSET], count * PCSX::Emulator::BIAS); // Add block cycles; + gen.add(dword[contextPointer + CYCLE_OFFSET], + (count + extra * PCSX::Emulator::ROM_EXTRA_BIAS) * PCSX::Emulator::BIAS); // Add block cycles; if (m_linkedPC && ENABLE_BLOCK_LINKING && m_linkedPC.value() != startingPC) { handleLinking(); } else { diff --git a/src/core/DynaRec_x86/iR3000A.cc b/src/core/DynaRec_x86/iR3000A.cc index 00273f6e2..20ee037df 100644 --- a/src/core/DynaRec_x86/iR3000A.cc +++ b/src/core/DynaRec_x86/iR3000A.cc @@ -3081,6 +3081,7 @@ void DynaRecCPU::recRecompile() { m_delayedLoadInfo[0].active = false; m_delayedLoadInfo[1].active = false; unsigned count = 0; + unsigned extra = 0; // Set up stack frame. // If our block doesn't require one, this will be emitted, but the block address will be adjusted so it won't be @@ -3138,6 +3139,7 @@ void DynaRecCPU::recRecompile() { m_regs.code = *(uint32_t *)p; m_pc += 4; count++; + if ((m_pc & 0xffc00000) == 0xbfc00000) extra++; func_t func = m_pRecBSC[m_regs.code >> 26]; (*this.*func)(); @@ -3155,7 +3157,7 @@ void DynaRecCPU::recRecompile() { processDelayedLoad(); iFlushRegs(); - gen.add(dword[&m_regs.cycle], count * PCSX::Emulator::BIAS); + gen.add(dword[&m_regs.cycle], (count + extra * PCSX::Emulator::ROM_EXTRA_BIAS) * PCSX::Emulator::BIAS); if (m_pcInEBP) { gen.mov(eax, ebp); diff --git a/src/core/psxemulator.h b/src/core/psxemulator.h index d77176eac..b8e0fcdbd 100644 --- a/src/core/psxemulator.h +++ b/src/core/psxemulator.h @@ -220,7 +220,8 @@ class Emulator { // takes one cycle, which is not the case on real hardware. // FIXME: Count the proper cycle and get rid of this static constexpr uint32_t m_psxClockSpeed = 33868800 /* 33.8688 MHz */; - enum { BIAS = 2 }; + static constexpr uint32_t BIAS = 2; + static constexpr uint32_t ROM_EXTRA_BIAS = 10; int init(); void reset(); diff --git a/src/core/psxinterpreter.cc b/src/core/psxinterpreter.cc index 04e02cb27..018785e7a 100644 --- a/src/core/psxinterpreter.cc +++ b/src/core/psxinterpreter.cc @@ -621,7 +621,7 @@ void InterpretedCPU::psxMULTU(uint32_t code) { * Format: OP rs, offset * *********************************************************/ #define RepZBranchi32(op) \ - if (int32_t(_rRs_) op 0) { \ + if (int32_t(_rRs_) op 0) { \ doBranch(_BranchTarget_, false); \ } #define RepZBranchLinki32(op) \ @@ -1613,6 +1613,7 @@ inline void InterpretedCPU::execBlock() { m_regs.pc += 4; m_regs.cycle += PCSX::Emulator::BIAS; + if ((m_regs.pc & 0xffc00000) == 0xbfc00000) m_regs.cycle += PCSX::Emulator::BIAS * 10; cIntFunc_t func = s_pPsxBSC[code >> 26]; (*this.*func)(code); From 6a696c1d9250cc49c42c857a9037b04389f77d87 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 22:10:01 -0800 Subject: [PATCH 102/185] Making a few games boot. --- src/core/cdrom.cc | 27 ++++++++++----------------- src/core/cdrom.h | 1 + 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 6c56b2995..4dfb25c66 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -107,6 +107,7 @@ class CDRomImpl final : public PCSX::CDRom { m_status = Status::IDLE; m_readDelayed = 0; m_dataRequested = false; + m_causeMask = 0x1f; } void interrupt() override { @@ -204,9 +205,13 @@ class CDRomImpl final : public PCSX::CDRom { void scheduleDMA(std::chrono::nanoseconds delay) { scheduleDMA(PCSX::psxRegisters::durationToCycles(delay)); } void triggerIRQ() { + assert(m_cause != Cause::None); assert(!m_waitingAck); - m_gotAck = false; - psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + uint8_t bit = 1 << (static_cast(m_cause) - 1); + if (m_causeMask & bit) { + m_gotAck = false; + psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + } } void clearIRQ() { psxHu32ref(0x1070) &= SWAP_LE32(~uint32_t(4)); } @@ -289,8 +294,7 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t read3() override { switch (m_registerIndex & 1) { case 0: { - // cause mask? this doesn't make sense. - return 0x1f; // derp? + return m_causeMask | 0xe0; } break; case 1: { // cause @@ -331,7 +335,6 @@ class CDRomImpl final : public PCSX::CDRom { case 3: { // Volume setting RR PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:3 not available yet\n"); - PCSX::g_system->pause(); } break; } } @@ -342,24 +345,15 @@ class CDRomImpl final : public PCSX::CDRom { if (paramFIFOAvailable()) m_paramFIFO[m_paramFIFOSize++] = value; } break; case 1: { - // cause mask - if (value == 0x1f) { - // all enabled? - // TODO: act on this? - return; - } - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:1 not available yet\n"); - PCSX::g_system->pause(); + m_causeMask = value; } break; case 2: { // Volume setting LL PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:2 not available yet\n"); - PCSX::g_system->pause(); } break; case 3: { // Volume setting RL PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:3 not available yet\n"); - PCSX::g_system->pause(); } break; } } @@ -419,12 +413,10 @@ class CDRomImpl final : public PCSX::CDRom { case 2: { // Volume setting LR PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:2 not available yet\n"); - PCSX::g_system->pause(); } break; case 3: { // SPU settings latch PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:3 not available yet\n"); - PCSX::g_system->pause(); } break; } } @@ -639,6 +631,7 @@ class CDRomImpl final : public PCSX::CDRom { m_invalidLocL = false; m_speed = Speed::Simple; m_status = Status::IDLE; + m_causeMask = 0x1f; memset(m_lastLocP, 0, sizeof(m_lastLocP)); if (!m_gotAck) { m_waitingAck = true; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index e0613c544..42b4f6d2a 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -140,6 +140,7 @@ class CDRom { uint8_t m_command = 0; enum class Speed : uint8_t { Simple, Double } m_speed; enum class ReadSpan : uint8_t { S2048, S2328, S2340 } m_readSpan; + uint8_t m_causeMask = 0x1f; enum class Cause : uint8_t { None = 0, From 129e0cfcbb66b42336318e23f80b4d170e8d8dac Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 22:32:02 -0800 Subject: [PATCH 103/185] Derp. --- src/core/cdrom.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 4dfb25c66..35951c04d 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -174,8 +174,8 @@ class CDRomImpl final : public PCSX::CDRom { m_readDelayed = 0; m_cause = Cause::DataReady; m_dataFIFOIndex = 0; - m_dataFIFOPending = 2048; - if (m_dataRequested) m_dataFIFOSize = 2048; + m_dataFIFOPending = size; + if (m_dataRequested) m_dataFIFOSize = size; m_currentPosition++; setResponse(getStatus()); triggerIRQ(); From eae7f845c2f150a5d57c90c0d7c86e0af372fbf0 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 22:32:16 -0800 Subject: [PATCH 104/185] Adding debugging output. --- src/core/cdrom.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 35951c04d..f12460286 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -137,8 +137,13 @@ class CDRomImpl final : public PCSX::CDRom { void readInterrupt() override { static const std::chrono::nanoseconds c_retryDelay = 50us; + const bool debug = PCSX::g_emulator->settings.get() + .get(); if ((m_status == Status::IDLE) || (m_status == Status::SEEKING)) { m_readDelayed = 0; + if (debug) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: cancelling read.\n"); + } return; } if (m_command != 0) { @@ -177,6 +182,10 @@ class CDRomImpl final : public PCSX::CDRom { m_dataFIFOPending = size; if (m_dataRequested) m_dataFIFOSize = size; m_currentPosition++; + if (debug) { + std::string msfFormat = fmt::format("{}", m_currentPosition); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: advancing to %s.\n", msfFormat); + } setResponse(getStatus()); triggerIRQ(); scheduleRead(readDelay); @@ -211,6 +220,12 @@ class CDRomImpl final : public PCSX::CDRom { if (m_causeMask & bit) { m_gotAck = false; psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + } else { + if (PCSX::g_emulator->settings.get() + .get()) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: wanted to trigger IRQ but cause %d is masked...\n", + static_cast(m_cause)); + } } } From 662e1cb3c55edd11883422eaa648584ed3316ec2 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 23:02:04 -0800 Subject: [PATCH 105/185] Derp. --- src/core/cdrom.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index f12460286..b86894c57 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -315,7 +315,6 @@ class CDRomImpl final : public PCSX::CDRom { // cause // TODO: add bit 4 uint8_t ret = magic_enum::enum_integer(m_cause) | 0xe0; - m_cause = Cause::None; return ret; } break; } @@ -403,6 +402,7 @@ class CDRomImpl final : public PCSX::CDRom { ack = true; } if (ack) { + m_cause = Cause::None; if (m_waitingAck) { m_waitingAck = false; schedule(350us); From 87e8e0331b73cfc3908a8b16346f73dd4db6c9ca Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 23:14:30 -0800 Subject: [PATCH 106/185] Adding harmless placeholders for Mute & Demute. --- src/core/cdrom.cc | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index b86894c57..73f5e5897 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -663,6 +663,28 @@ class CDRomImpl final : public PCSX::CDRom { } } + // Command 11 + void cdlMute() { + // TODO: probably should error out if no disc or + // lid open? + setResponse(getStatus()); + m_cause = Cause::Acknowledge; + m_command = 0; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: Mute - not yet implemented.\n"); + triggerIRQ(); + } + + // Command 12 + void cdlDemute() { + // TODO: probably should error out if no disc or + // lid open? + setResponse(getStatus()); + m_cause = Cause::Acknowledge; + m_command = 0; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: Demute - not yet implemented.\n"); + triggerIRQ(); + } + // Command 14 void cdlSetMode() { uint8_t mode = m_paramFIFO[0]; @@ -930,8 +952,8 @@ class CDRomImpl final : public PCSX::CDRom { #else nullptr, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, nullptr, // 0 nullptr, nullptr, &CDRomImpl::cdlReadN, nullptr, // 4 - nullptr, &CDRomImpl::cdlPause, &CDRomImpl::cdlInit, nullptr, // 8 - nullptr, nullptr, &CDRomImpl::cdlSetMode, nullptr, // 12 + nullptr, &CDRomImpl::cdlPause, &CDRomImpl::cdlInit, &CDRomImpl::cdlMute, // 8 + &CDRomImpl::cdlDemute, nullptr, &CDRomImpl::cdlSetMode, nullptr, // 12 &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, nullptr, &CDRomImpl::cdlGetTN, // 16 &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, nullptr, // 20 nullptr, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, nullptr, // 24 @@ -951,14 +973,14 @@ class CDRomImpl final : public PCSX::CDRom { }; static constexpr std::chrono::nanoseconds c_commandsInitialDelay[31] = { - 0ns, 750us, 1ms, 0ns, // 0 - 0ns, 0ns, 1ms, 0ns, // 4 - 0ns, 1ms, 2ms, 0ns, // 8 - 0ns, 0ns, 750us, 0ns, // 12 - 750us, 750us, 0ns, 2ms, // 16 - 750us, 1ms, 1ms, 0ns, // 20 - 0ns, 750us, 5ms, 0ns, // 24 - 0ns, 0ns, 0ns, // 28 + 0ns, 750us, 1ms, 0ns, // 0 + 0ns, 0ns, 1ms, 0ns, // 4 + 0ns, 1ms, 2ms, 750us, // 8 + 750us, 0ns, 750us, 0ns, // 12 + 750us, 750us, 0ns, 2ms, // 16 + 750us, 1ms, 1ms, 0ns, // 20 + 0ns, 750us, 5ms, 0ns, // 24 + 0ns, 0ns, 0ns, // 28 }; void logCDROM(uint8_t command) { From 7a47e175f3590c76e154b114efa6878d1fc408c5 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 23:34:25 -0800 Subject: [PATCH 107/185] Derp. --- src/core/cdrom.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 73f5e5897..62ca3a128 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -171,7 +171,7 @@ class CDRomImpl final : public PCSX::CDRom { break; case ReadSpan::S2340: size = 2340; - memcpy(m_dataFIFO, buffer + 4, 2340); + memcpy(m_dataFIFO, buffer, 2340); break; } auto readDelay = computeReadDelay(); From 4794dac7ccb42fd75a0c9d867ed6e7267fe3ab58 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 28 Dec 2022 23:34:51 -0800 Subject: [PATCH 108/185] Properly implementing getLocL. --- src/core/cdrom.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 62ca3a128..2b6119a29 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -153,8 +153,10 @@ class CDRomImpl final : public PCSX::CDRom { } switch (m_status) { case Status::READING_DATA: { + m_invalidLocL = false; m_iso->readTrack(m_currentPosition); auto buffer = m_iso->getBuffer(); + memcpy(m_lastLocL, buffer, sizeof(m_lastLocL)); uint32_t size = 0; switch (m_readSpan) { case ReadSpan::S2048: @@ -609,6 +611,7 @@ class CDRomImpl final : public PCSX::CDRom { } break; case 2: m_status = Status::IDLE; + m_invalidLocL = true; if (!m_gotAck) { m_waitingAck = true; m_state = 3; From 394f0832145ea03a8fcb528576ae601a2c5043c9 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 09:37:22 -0800 Subject: [PATCH 109/185] Adding filtering / xa bits into setmode. --- src/core/cdrom.cc | 6 +++++- src/core/cdrom.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 2b6119a29..b2572abe2 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -108,6 +108,8 @@ class CDRomImpl final : public PCSX::CDRom { m_readDelayed = 0; m_dataRequested = false; m_causeMask = 0x1f; + m_subheaderFilter = false; + m_realtime = false; } void interrupt() override { @@ -718,7 +720,9 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->pause(); break; } - if (mode & 0x4f) { + m_subheaderFilter = (mode & 0x08) != 0; + m_realtime = (mode & 0x40) != 0; + if (mode & 0x07) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode:\n", mode); PCSX::g_system->pause(); } diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 42b4f6d2a..9e4846029 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -130,6 +130,8 @@ class CDRom { bool m_speedChanged = false; bool m_invalidLocL = false; bool m_dataRequested = false; + bool m_subheaderFilter = false; + bool m_realtime = false; enum class Status : uint8_t { IDLE, READING_DATA, From 56ceed8247737a8c9154b28863457f50e3ee62cb Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 09:37:53 -0800 Subject: [PATCH 110/185] Adding ReadS. Just a copy of ReadN. Might need to coalesce the functions later. --- src/core/cdrom.cc | 50 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index b2572abe2..0c9590416 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -944,6 +944,52 @@ class CDRomImpl final : public PCSX::CDRom { } } + // Command 27. + void cdlReadS() { + switch (m_state) { + case 1: { + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; + } + schedule(seekDelay); + m_cause = Cause::Acknowledge; + m_state = 2; + setResponse(getStatus()); + m_status = Status::SEEKING; + triggerIRQ(); + } break; + case 2: + m_status = Status::IDLE; + if (!m_gotAck) { + m_waitingAck = true; + m_state = 3; + break; + } + [[fallthrough]]; + case 3: { + m_currentPosition = m_seekPosition; + unsigned track = m_iso->getTrack(m_seekPosition); + if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(4); + triggerIRQ(); + } else if (track == 0) { + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(0x10); + triggerIRQ(); + } else { + m_status = Status::READING_DATA; + scheduleRead(computeReadDelay()); + } + m_command = 0; + } break; + } + } + typedef void (CDRomImpl::*CommandType)(); const CommandType c_commandsHandlers[31] { @@ -963,7 +1009,7 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlDemute, nullptr, &CDRomImpl::cdlSetMode, nullptr, // 12 &CDRomImpl::cdlGetLocL, &CDRomImpl::cdlGetLocP, nullptr, &CDRomImpl::cdlGetTN, // 16 &CDRomImpl::cdlGetTD, &CDRomImpl::cdlSeekL, &CDRomImpl::cdlSeekP, nullptr, // 20 - nullptr, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, nullptr, // 24 + nullptr, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 nullptr, nullptr, nullptr, // 28 #endif }; @@ -986,7 +1032,7 @@ class CDRomImpl final : public PCSX::CDRom { 750us, 0ns, 750us, 0ns, // 12 750us, 750us, 0ns, 2ms, // 16 750us, 1ms, 1ms, 0ns, // 20 - 0ns, 750us, 5ms, 0ns, // 24 + 0ns, 750us, 5ms, 1ms, // 24 0ns, 0ns, 0ns, // 28 }; From f2fdf8c0e291d496d8922b9437ec80af0b45f8b1 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 09:47:41 -0800 Subject: [PATCH 111/185] Fixing cdlID. --- src/core/cdrom.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 0c9590416..021599f0b 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -937,7 +937,10 @@ class CDRomImpl final : public PCSX::CDRom { // Adjust this response for various types of discs and situations. m_cause = Cause::Complete; setResponse(getStatus()); - appendResponse("\x00\x20\x00PCSX"); + appendResponse(0x00); + appendResponse(0x20); + appendResponse(0x00); + appendResponse("PCSX"sv); m_command = 0; triggerIRQ(); } break; From 56afe7c7e72135d8036691b4b278d2d47082eddd Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 13:13:16 -0800 Subject: [PATCH 112/185] Adding CD-Rom hardware logging. --- src/core/cdrom.cc | 108 ++++++++++++++++++++++++++++++++--------- src/core/psxemulator.h | 13 ++--- src/gui/widgets/log.cc | 2 + 3 files changed, 93 insertions(+), 30 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 021599f0b..ea511ab1e 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -224,6 +224,13 @@ class CDRomImpl final : public PCSX::CDRom { if (m_causeMask & bit) { m_gotAck = false; psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] triggering IRQ with cause %d\n", regs.pc, + regs.cycle, static_cast(m_cause)); + } } else { if (PCSX::g_emulator->settings.get() .get()) { @@ -233,8 +240,6 @@ class CDRomImpl final : public PCSX::CDRom { } } - void clearIRQ() { psxHu32ref(0x1070) &= SWAP_LE32(~uint32_t(4)); } - void setResponse(std::string_view response) { std::copy(response.begin(), response.end(), m_responseFIFO); m_responseFIFOSize = response.size(); @@ -284,6 +289,12 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t v7 = m_busy ? 0x80 : 0; uint8_t ret = v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7; + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] r0: %02x\n", regs.pc, regs.cycle, ret); + } return ret; } @@ -296,6 +307,12 @@ class CDRomImpl final : public PCSX::CDRom { ret = m_responseFIFO[m_responseFIFOIndex++]; } + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] r1: %02x\n", regs.pc, regs.cycle, ret); + } return ret; } @@ -307,28 +324,55 @@ class CDRomImpl final : public PCSX::CDRom { ret = m_dataFIFO[m_dataFIFOIndex++]; } + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] r2: %02x\n", regs.pc, regs.cycle, ret); + } return ret; } uint8_t read3() override { + uint8_t ret = 0; switch (m_registerIndex & 1) { case 0: { - return m_causeMask | 0xe0; + ret = m_causeMask | 0xe0; } break; case 1: { // cause // TODO: add bit 4 - uint8_t ret = magic_enum::enum_integer(m_cause) | 0xe0; - return ret; + ret = magic_enum::enum_integer(m_cause) | 0xe0; } break; } - // should not be reachable - return 0; + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] r3.%i: %02x\n", regs.pc, regs.cycle, + m_registerIndex & 1, ret); + } + return ret; } - void write0(uint8_t value) override { m_registerIndex = value & 3; } + void write0(uint8_t value) override { + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w0: %02x\n", regs.pc, regs.cycle, value); + } + m_registerIndex = value & 3; + } void write1(uint8_t value) override { + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w1.%i: %02x\n", regs.pc, regs.cycle, + m_registerIndex, value); + } switch (m_registerIndex) { case 0: { if (m_busy) { @@ -358,6 +402,13 @@ class CDRomImpl final : public PCSX::CDRom { } void write2(uint8_t value) override { + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w2.%i: %02x\n", regs.pc, regs.cycle, + m_registerIndex, value); + } switch (m_registerIndex) { case 0: { if (paramFIFOAvailable()) m_paramFIFO[m_paramFIFOSize++] = value; @@ -377,6 +428,13 @@ class CDRomImpl final : public PCSX::CDRom { } void write3(uint8_t value) override { + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w3.%i: %02x\n", regs.pc, regs.cycle, + m_registerIndex, value); + } switch (m_registerIndex) { case 0: { // ?? @@ -1040,23 +1098,25 @@ class CDRomImpl final : public PCSX::CDRom { }; void logCDROM(uint8_t command) { - uint32_t pc = PCSX::g_emulator->m_cpu->m_regs.pc; + auto ®s = PCSX::g_emulator->m_cpu->m_regs; switch (command & 0xff) { case CdlTest: - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlTest %02x\n", pc, m_paramFIFO[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlTest %02x\n", regs.pc, + regs.cycle, m_paramFIFO[0]); break; case CdlSetLoc: - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlSetloc %02x:%02x:%02x\n", pc, - m_paramFIFO[0], m_paramFIFO[1], m_paramFIFO[2]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlSetloc %02x:%02x:%02x\n", + regs.pc, regs.cycle, m_paramFIFO[0], m_paramFIFO[1], m_paramFIFO[2]); break; case CdlPlay: - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlPlay %i\n", pc, m_paramFIFO[0]); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlPlay %i\n", regs.pc, + regs.cycle, m_paramFIFO[0]); break; case CdlSetFilter: PCSX::g_system->log(PCSX::LogClass::CDROM, - "CD-Rom: %08x] Command: CdlSetfilter file: %i, channel: %i\n", pc, m_paramFIFO[0], - m_paramFIFO[1]); + "CD-Rom: %08x.%08x] Command: CdlSetfilter file: %i, channel: %i\n", regs.pc, + regs.cycle, m_paramFIFO[0], m_paramFIFO[1]); break; case CdlSetMode: { auto mode = m_paramFIFO[0]; @@ -1080,25 +1140,25 @@ class CDRomImpl final : public PCSX::CDRom { } if (mode & 0x40) modeDecode += " RealTimePlay"; modeDecode += mode & 0x80 ? " @2x" : " @1x"; - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlSetmode %02x (%s)\n", pc, - m_paramFIFO[0], modeDecode); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlSetmode %02x (%s)\n", + regs.pc, regs.cycle, m_paramFIFO[0], modeDecode); } break; case CdlGetTN: - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlGetTN (returns %i)\n", pc, - m_iso->getTN()); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlGetTN (returns %i)\n", + regs.pc, regs.cycle, m_iso->getTN()); break; case CdlGetTD: { auto ret = m_iso->getTD(m_paramFIFO[0]); PCSX::g_system->log(PCSX::LogClass::CDROM, - "CD-Rom: %08x] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", pc, m_paramFIFO[0], - ret.m, ret.s, ret.f); + "CD-Rom: %08x.%08x] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", regs.pc, + regs.cycle, m_paramFIFO[0], ret.m, ret.s, ret.f); } break; default: if ((command & 0xff) > c_cdCmdEnumCount) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: CdlUnknown(0x%02X)\n", pc, - command & 0xff); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlUnknown(0x%02X)\n", + regs.pc, regs.cycle, command & 0xff); } else { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x] Command: %s\n", pc, + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: %s\n", regs.pc, regs.cycle, magic_enum::enum_names()[command & 0xff]); } break; diff --git a/src/core/psxemulator.h b/src/core/psxemulator.h index b8e0fcdbd..ae9f81ed0 100644 --- a/src/core/psxemulator.h +++ b/src/core/psxemulator.h @@ -104,6 +104,7 @@ class Emulator { typedef Setting FirstChanceException; typedef Setting SkipISR; typedef Setting LoggingCDROM; + typedef Setting LoggingHWCDROM; typedef Setting GdbServer; typedef Setting GdbManifest; enum class GdbLog { @@ -138,12 +139,12 @@ class Emulator { Raw, }; typedef Setting SIO1ModeSetting; - typedef Settings + typedef Settings type; }; typedef SettingNested SettingDebugSettings; diff --git a/src/gui/widgets/log.cc b/src/gui/widgets/log.cc index fba44254f..63ab491fe 100644 --- a/src/gui/widgets/log.cc +++ b/src/gui/widgets/log.cc @@ -107,6 +107,8 @@ bool PCSX::Widgets::Log::draw(GUI* gui, const char* title) { auto& debugSettings = g_emulator->settings.get(); changed |= ImGui::MenuItem(_("Log CD-ROM commands"), nullptr, &debugSettings.get().value); + changed |= ImGui::MenuItem(_("Log CD-ROM hardware access"), nullptr, + &debugSettings.get().value); changed |= ImGui::MenuItem(_("CPU trace"), nullptr, &debugSettings.get().value); changed |= ImGui::MenuItem(_("Skip ISR during CPU traces"), nullptr, From 2169b06360de5190bcfd792c827bc45a4e23cbc1 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 22:05:18 -0800 Subject: [PATCH 113/185] Adding ReadS tests. --- src/mips/tests/cdrom/cdlreads.c | 842 ++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdrom.c | 1 + 2 files changed, 843 insertions(+) create mode 100644 src/mips/tests/cdrom/cdlreads.c diff --git a/src/mips/tests/cdrom/cdlreads.c b/src/mips/tests/cdrom/cdlreads.c new file mode 100644 index 000000000..a5c99cb0b --- /dev/null +++ b/src/mips/tests/cdrom/cdlreads.c @@ -0,0 +1,842 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlReadS1x, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + uint32_t size = 0; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + while ((CDROM_REG0 & 0x40) == 0); + while (((CDROM_REG0 & 0x40) != 0) && (size < 6)) { + sector[size++] = CDROM_REG2; + } + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime2; + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Pausing at 1x is ~70ms + cester_assert_uint_ge(completeTime, 65000); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + cester_assert_uint_eq(6, size); + ramsyscall_printf("Basic single 6 bytes readS @1x at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadS1xwithDMA, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + uint32_t dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x00880000; + DICR = dicr; + DPCR |= 0x8000; + DMA_CTRL[DMA_CDROM].MADR = (uintptr_t)sector; + DMA_CTRL[DMA_CDROM].BCR = (2048 >> 2) | 0x10000; + DMA_CTRL[DMA_CDROM].CHCR = 0x11000000; + + while ((DMA_CTRL[DMA_CDROM].CHCR & 0x01000000) != 0); + dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x88000000; + DICR = dicr; + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime2; + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Pausing at 1x is ~70ms + cester_assert_uint_ge(completeTime, 65000); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + ramsyscall_printf("Basic single full sector readS @1x with DMA at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadS2x, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + uint32_t size = 0; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + while ((CDROM_REG0 & 0x40) == 0); + while (((CDROM_REG0 & 0x40) != 0) && (size < 6)) { + sector[size++] = CDROM_REG2; + } + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime2; + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Switching speed is roughly 650ms for the speed up, + // and then this also contains the seeking time, and + // the time to read the first sector, which is 6.66ms + cester_assert_uint_ge(readyTime, 500000); + // Pausing at 2x is ~35ms + cester_assert_uint_ge(completeTime, 32500); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + cester_assert_uint_eq(6, size); + ramsyscall_printf("Basic single 6 bytes readS @2x at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadS2xwithDMA, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + uint32_t dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x00880000; + DICR = dicr; + DPCR |= 0x8000; + DMA_CTRL[DMA_CDROM].MADR = (uintptr_t)sector; + DMA_CTRL[DMA_CDROM].BCR = (2048 >> 2) | 0x10000; + DMA_CTRL[DMA_CDROM].CHCR = 0x11000000; + + while ((DMA_CTRL[DMA_CDROM].CHCR & 0x01000000) != 0); + dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x88000000; + DICR = dicr; + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime2; + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Switching speed is roughly 650ms for the speed up, + // and then this also contains the seeking time, and + // the time to read the first sector, which is 6.66ms + cester_assert_uint_ge(readyTime, 500000); + // Pausing at 2x is ~35ms + cester_assert_uint_ge(completeTime, 32500); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + ramsyscall_printf("Basic single full sector readS @2x with DMA at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadS2xRunaway, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2048]; + uint32_t size = 0; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + while ((CDROM_REG0 & 0x40) == 0); + while (((CDROM_REG0 & 0x40) != 0) && (size < 6)) { + sector[size++] = CDROM_REG2; + } + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime2; + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + CDROM_REG0 = 0; + CDROM_REG3 = 0; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x78, ctrl5); + cester_assert_uint_eq(0x58, ctrl6); + cester_assert_uint_eq(0x78, ctrl7); + cester_assert_uint_eq(0x58, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Switching speed is roughly 650ms for the speed up, + // and then this also contains the seeking time, and + // the time to read the first sector, which is 6.66ms + cester_assert_uint_ge(readyTime, 500000); + // Pausing at 2x is ~35ms + cester_assert_uint_ge(completeTime, 32500); + cester_assert_uint_eq(1, sector[0]); + cester_assert_uint_eq('C', sector[1]); + cester_assert_uint_eq('D', sector[2]); + cester_assert_uint_eq('0', sector[3]); + cester_assert_uint_eq('0', sector[4]); + cester_assert_uint_eq('1', sector[5]); + cester_assert_uint_eq(6, size); + ramsyscall_printf("Basic single 6 bytes readS @2x at 00:02:16, runaway read, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + +CESTER_TEST(cdlReadSInAudio, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0x70, 0x21, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t errorTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(4, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + cester_assert_uint_ge(errorTime, 4000000); + ramsyscall_printf("Basic readS in audio track, ack in %ius, errored in %ius\n", ackTime, errorTime); +) + +CESTER_TEST(cdlReadSTooFar, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0x80, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t errorTime = waitCDRomIRQ() - ackTime; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(0x10, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + cester_assert_uint_ge(errorTime, 600000); + ramsyscall_printf("Basic readS too far, ack in %ius, errored in %ius\n", ackTime, errorTime); +) + +CESTER_TEST(cdlReadS2xWithNop, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0x70, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READS; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + + uint8_t ctrl2b = CDROM_REG0 & ~3; + + uint32_t ackTime2 = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint32_t readyTime = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime3 = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime3; + uint8_t cause5 = ackCDRomCause(); + uint8_t ctrl9 = CDROM_REG0 & ~3; + uint8_t response5[16]; + uint8_t responseSize5 = readResponse(response5); + uint8_t ctrl10 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause5b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(1, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(3, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(2, cause5); + cester_assert_uint_eq(0xe0, cause5b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x18, ctrl2b); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(0x38, ctrl9); + cester_assert_uint_eq(0x18, ctrl10); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(0x22, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(2, response5[0]); + cester_assert_uint_eq(1, responseSize5); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + cester_assert_uint_ge(ackTime3, 500); + cester_assert_uint_lt(ackTime3, 7000); + cester_assert_uint_ge(readyTime, 500000); + cester_assert_uint_ge(completeTime, 32500); + ramsyscall_printf("Basic single full sector readS @2x with DMA at 70:00:00 with nop interleaved, ack1 in %ius, ack2 in %ius, ready in %ius, ack3 in %ius, complete in %ius\n", ackTime1, ackTime2, readyTime, ackTime3, completeTime); +) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 5b7f31b0a..a34af1f27 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -45,6 +45,7 @@ SOFTWARE. #include "cdlid.c" #include "cdlinit.c" #include "cdlreadn.c" +#include "cdlreads.c" #include "cdlseekl.c" #include "cdlseekp.c" #include "cdlsetloc.c" From 94eaf9ad6b943f3f8f8f425068778189daff5ae1 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 22:59:03 -0800 Subject: [PATCH 114/185] Making test pass. --- src/core/cdrom.cc | 219 ++++++++++++++++++---------------------------- src/core/cdrom.h | 17 ++-- 2 files changed, 98 insertions(+), 138 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index ea511ab1e..ce8979874 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -104,7 +104,7 @@ class CDRomImpl final : public PCSX::CDRom { m_waitingAck = false; m_speed = Speed::Simple; m_speedChanged = false; - m_status = Status::IDLE; + m_status = Status::Idle; m_readDelayed = 0; m_dataRequested = false; m_causeMask = 0x1f; @@ -141,58 +141,80 @@ class CDRomImpl final : public PCSX::CDRom { static const std::chrono::nanoseconds c_retryDelay = 50us; const bool debug = PCSX::g_emulator->settings.get() .get(); - if ((m_status == Status::IDLE) || (m_status == Status::SEEKING)) { + if (m_startReading) { + m_startReading = false; + m_status = Status::ReadingData; + } + if ((m_status == Status::Idle) || (m_status == Status::Seeking)) { m_readDelayed = 0; + m_readingType = ReadingType::None; if (debug) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: cancelling read.\n"); } return; } + if (m_command != 0) { m_readDelayed++; scheduleRead(c_retryDelay); return; } switch (m_status) { - case Status::READING_DATA: { - m_invalidLocL = false; - m_iso->readTrack(m_currentPosition); - auto buffer = m_iso->getBuffer(); - memcpy(m_lastLocL, buffer, sizeof(m_lastLocL)); - uint32_t size = 0; - switch (m_readSpan) { - case ReadSpan::S2048: - size = 2048; - if (buffer[3] == 1) { - memcpy(m_dataFIFO, buffer + 4, 2048); - } else { - memcpy(m_dataFIFO, buffer + 12, 2048); - } - break; - case ReadSpan::S2328: - size = 2328; - memcpy(m_dataFIFO, buffer + 12, 2328); - break; - case ReadSpan::S2340: - size = 2340; - memcpy(m_dataFIFO, buffer, 2340); - break; - } - auto readDelay = computeReadDelay(); - readDelay -= m_readDelayed * c_retryDelay; - m_readDelayed = 0; - m_cause = Cause::DataReady; - m_dataFIFOIndex = 0; - m_dataFIFOPending = size; - if (m_dataRequested) m_dataFIFOSize = size; - m_currentPosition++; - if (debug) { - std::string msfFormat = fmt::format("{}", m_currentPosition); - PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: advancing to %s.\n", msfFormat); + case Status::ReadingData: { + unsigned track = m_iso->getTrack(m_currentPosition); + if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { + m_status = Status::Idle; + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(4); + triggerIRQ(); + } else if (track == 0) { + m_status = Status::Idle; + m_cause = Cause::Error; + setResponse(getStatus() | 4); + appendResponse(0x10); + triggerIRQ(); + } else { + m_invalidLocL = false; + m_iso->readTrack(m_currentPosition); + auto buffer = m_iso->getBuffer(); + memcpy(m_lastLocL, buffer, sizeof(m_lastLocL)); + uint32_t size = 0; + switch (m_readSpan) { + case ReadSpan::S2048: + size = 2048; + if (buffer[3] == 1) { + memcpy(m_dataFIFO, buffer + 4, 2048); + } else { + memcpy(m_dataFIFO, buffer + 12, 2048); + } + break; + case ReadSpan::S2328: + size = 2328; + memcpy(m_dataFIFO, buffer + 12, 2328); + break; + case ReadSpan::S2340: + size = 2340; + memcpy(m_dataFIFO, buffer, 2340); + break; + } + auto readDelay = computeReadDelay(); + readDelay -= m_readDelayed * c_retryDelay; + m_readDelayed = 0; + m_cause = Cause::DataReady; + m_dataFIFOIndex = 0; + m_dataFIFOPending = size; + if (m_dataRequested) m_dataFIFOSize = size; + m_currentPosition++; + if (debug) { + std::string msfFormat = fmt::format("{}", m_currentPosition); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: advancing to %s.\n", + msfFormat); + } + setResponse(getStatus()); + triggerIRQ(); + scheduleRead(readDelay); } - setResponse(getStatus()); - triggerIRQ(); - scheduleRead(readDelay); } break; default: PCSX::g_system->log(PCSX::LogClass::CDROM, "unsupported yet\n"); @@ -266,13 +288,13 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t v4 = m_wasLidOpened ? 0x10 : 0; uint8_t v567 = 0; switch (m_status) { - case Status::READING_DATA: + case Status::ReadingData: v567 = 0x20; break; - case Status::SEEKING: + case Status::Seeking: v567 = 0x40; break; - case Status::PLAYING_CDDA: + case Status::PlayingCDDA: v567 = 0x80; break; } @@ -611,55 +633,26 @@ class CDRomImpl final : public PCSX::CDRom { // Command 6. void cdlReadN() { - switch (m_state) { - case 1: { - auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); - if (m_speedChanged) { - m_speedChanged = false; - seekDelay += 650ms; - } - schedule(seekDelay); - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - m_status = Status::SEEKING; - triggerIRQ(); - } break; - case 2: - m_status = Status::IDLE; - if (!m_gotAck) { - m_waitingAck = true; - m_state = 3; - break; - } - [[fallthrough]]; - case 3: { - m_currentPosition = m_seekPosition; - unsigned track = m_iso->getTrack(m_seekPosition); - if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(4); - triggerIRQ(); - } else if (track == 0) { - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(0x10); - triggerIRQ(); - } else { - m_status = Status::READING_DATA; - scheduleRead(computeReadDelay()); - } - m_command = 0; - } break; + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; } + scheduleRead(seekDelay + computeReadDelay()); + m_cause = Cause::Acknowledge; + setResponse(getStatus()); + m_currentPosition = m_seekPosition; + m_command = 0; + m_startReading = true; + m_readingType = ReadingType::Normal; + triggerIRQ(); } // Command 9. void cdlPause() { switch (m_state) { case 1: { - if (m_status == Status::IDLE) { + if (m_status == Status::Idle) { schedule(200us); } else { schedule(m_speed == Speed::Simple ? 70ms : 35ms); @@ -670,7 +663,7 @@ class CDRomImpl final : public PCSX::CDRom { triggerIRQ(); } break; case 2: - m_status = Status::IDLE; + m_status = Status::Idle; m_invalidLocL = true; if (!m_gotAck) { m_waitingAck = true; @@ -708,7 +701,7 @@ class CDRomImpl final : public PCSX::CDRom { m_seekPosition.s = 2; m_invalidLocL = false; m_speed = Speed::Simple; - m_status = Status::IDLE; + m_status = Status::Idle; m_causeMask = 0x1f; memset(m_lastLocP, 0, sizeof(m_lastLocP)); if (!m_gotAck) { @@ -864,11 +857,11 @@ class CDRomImpl final : public PCSX::CDRom { m_speedChanged = false; seekDelay += 650ms; } - m_status = Status::SEEKING; + m_status = Status::Seeking; schedule(seekDelay); break; case 2: - m_status = Status::IDLE; + m_status = Status::Idle; if (!m_gotAck) { m_waitingAck = true; m_state = 3; @@ -910,11 +903,11 @@ class CDRomImpl final : public PCSX::CDRom { m_speedChanged = false; seekDelay += 650ms; } - m_status = Status::SEEKING; + m_status = Status::Seeking; schedule(seekDelay); break; case 2: - m_status = Status::IDLE; + m_status = Status::Idle; if (!m_gotAck) { m_waitingAck = true; m_state = 3; @@ -1007,48 +1000,8 @@ class CDRomImpl final : public PCSX::CDRom { // Command 27. void cdlReadS() { - switch (m_state) { - case 1: { - auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); - if (m_speedChanged) { - m_speedChanged = false; - seekDelay += 650ms; - } - schedule(seekDelay); - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - m_status = Status::SEEKING; - triggerIRQ(); - } break; - case 2: - m_status = Status::IDLE; - if (!m_gotAck) { - m_waitingAck = true; - m_state = 3; - break; - } - [[fallthrough]]; - case 3: { - m_currentPosition = m_seekPosition; - unsigned track = m_iso->getTrack(m_seekPosition); - if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(4); - triggerIRQ(); - } else if (track == 0) { - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(0x10); - triggerIRQ(); - } else { - m_status = Status::READING_DATA; - scheduleRead(computeReadDelay()); - } - m_command = 0; - } break; - } + cdlReadN(); + m_readingType = ReadingType::Streaming; } typedef void (CDRomImpl::*CommandType)(); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 9e4846029..641897238 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -132,12 +132,19 @@ class CDRom { bool m_dataRequested = false; bool m_subheaderFilter = false; bool m_realtime = false; + bool m_startReading = false; + bool m_startPlaying = false; + enum class ReadingType : uint8_t { + None, + Normal, + Streaming, + } m_readingType = ReadingType::None; enum class Status : uint8_t { - IDLE, - READING_DATA, - SEEKING, - PLAYING_CDDA, - } m_status = Status::IDLE; + Idle, + ReadingData, + Seeking, + PlayingCDDA, + } m_status = Status::Idle; uint8_t m_state = 0; uint8_t m_command = 0; enum class Speed : uint8_t { Simple, Double } m_speed; From cf0b6db28a97365e3896ae113103b00f5fa8a91f Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 23:33:32 -0800 Subject: [PATCH 115/185] The busy flag seems just wrong. --- src/core/cdrom.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index ce8979874..11de289c6 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -397,11 +397,12 @@ class CDRomImpl final : public PCSX::CDRom { } switch (m_registerIndex) { case 0: { - if (m_busy) { + if (m_command != 0) { // The CD-Rom controller is already executing a command. // This basically results in undefined behavior. We'll still // have to address this, as some games will do it anyway. - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: command while controller is busy\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, + "CD-Rom: command while controller is already executing one!\n"); PCSX::g_system->pause(); } startCommand(value); From 983a245b07b1317921f03b16a35326d3726af7e4 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Thu, 29 Dec 2022 23:56:59 -0800 Subject: [PATCH 116/185] Fixing Unix build. --- src/core/cdrom.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 11de289c6..b7aa224c4 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -848,7 +848,7 @@ class CDRomImpl final : public PCSX::CDRom { // Command 21. void cdlSeekL() { switch (m_state) { - case 1: + case 1: { m_cause = Cause::Acknowledge; m_state = 2; setResponse(getStatus()); @@ -860,7 +860,7 @@ class CDRomImpl final : public PCSX::CDRom { } m_status = Status::Seeking; schedule(seekDelay); - break; + } break; case 2: m_status = Status::Idle; if (!m_gotAck) { @@ -894,7 +894,7 @@ class CDRomImpl final : public PCSX::CDRom { // Command 22. void cdlSeekP() { switch (m_state) { - case 1: + case 1: { m_cause = Cause::Acknowledge; m_state = 2; setResponse(getStatus()); @@ -906,7 +906,7 @@ class CDRomImpl final : public PCSX::CDRom { } m_status = Status::Seeking; schedule(seekDelay); - break; + } break; case 2: m_status = Status::Idle; if (!m_gotAck) { From 214551182baf3abdd52f8140883c759b7d4df07f Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 30 Dec 2022 09:52:54 -0800 Subject: [PATCH 117/185] Adding some racy tests. --- src/mips/tests/cdrom/cdrom.c | 2 + src/mips/tests/cdrom/cester-hw.c | 12 ++ src/mips/tests/cdrom/race.c | 206 +++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 src/mips/tests/cdrom/race.c diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index a34af1f27..41cfddc11 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -38,6 +38,7 @@ SOFTWARE. #include "exotic/cester.h" #include "cester-hw.c" + #include "cdlgetlocl.c" #include "cdlgetlocp.c" #include "cdlgettd.c" @@ -52,3 +53,4 @@ SOFTWARE. #include "cdlsetmode.c" #include "cdltest.c" #include "invalid.c" +#include "race.c" diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index 910a9b8bd..bd88ca18c 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -104,6 +104,18 @@ CESTER_BODY( return time; } + static inline int waitCDRomIRQWithTimeout(uint32_t* timeoutp) { + uint32_t time = updateTime(); + uint32_t timeout = *timeoutp + time; + do { + time = updateTime(); + } while (((IREG & IRQ_CDROM) == 0) && (time <= timeout)); + int ret = (IREG & IRQ_CDROM) != 0; + *timeoutp = time; + IREG &= ~IRQ_CDROM; + return ret; + } + static inline uint8_t ackCDRomCause() { CDROM_REG0 = 1; uint8_t cause = CDROM_REG3_UC; diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c new file mode 100644 index 000000000..3efb287fe --- /dev/null +++ b/src/mips/tests/cdrom/race.c @@ -0,0 +1,206 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(raceGetLocPAndNop, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + CDROM_REG1 = CDL_NOP; + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t timeout = 150000; + int gotIRQ = waitCDRomIRQWithTimeout(&timeout); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_false(gotIRQ); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("GetLocP followed by Nop, ack in %ius\n", ackTime); +) + +CESTER_TEST(raceNopAndGetLocP, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + CDROM_REG1 = CDL_GETLOCP; + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t timeout = 150000; + int gotIRQ = waitCDRomIRQWithTimeout(&timeout); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(5, response1[0]); + cester_assert_uint_eq(0, response1[1]); + cester_assert_uint_eq(8, responseSize1); + cester_assert_false(gotIRQ); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Nop followed by GetLocP, ack in %ius\n", ackTime); +) + +CESTER_TEST(raceNopAndGetTD1, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 1; + CDROM_REG1 = CDL_NOP; + CDROM_REG1 = CDL_GETTD; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t timeout = 150000; + int gotIRQ = waitCDRomIRQWithTimeout(&timeout); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0, response1[1]); + cester_assert_uint_eq(2, response1[2]); + cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_false(gotIRQ); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) + + +CESTER_TEST(raceGetTD1AndNop, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG2 = 1; + CDROM_REG1 = CDL_GETTD; + CDROM_REG1 = CDL_NOP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t timeout = 150000; + int gotIRQ = waitCDRomIRQWithTimeout(&timeout); + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_false(gotIRQ); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + + IMASK = imask; +) From b8938dd0699e0d1e73e80c5d41711c77bb512e98 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 30 Dec 2022 10:16:36 -0800 Subject: [PATCH 118/185] Adding more racy tests. --- src/mips/tests/cdrom/race.c | 110 +++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 3 deletions(-) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 3efb287fe..28f6d49b9 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -43,6 +43,8 @@ CESTER_TEST(raceGetLocPAndNop, test_instances, CDROM_REG0 = 0; CDROM_REG1 = CDL_GETLOCP; CDROM_REG1 = CDL_NOP; + uint8_t ctrl0 = CDROM_REG0 & ~3; + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; @@ -58,6 +60,7 @@ CESTER_TEST(raceGetLocPAndNop, test_instances, cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x98, ctrl0); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(2, response1[0]); @@ -85,6 +88,8 @@ CESTER_TEST(raceNopAndGetLocP, test_instances, CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; CDROM_REG1 = CDL_GETLOCP; + uint8_t ctrl0 = CDROM_REG0 & ~3; + uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); uint8_t ctrl1 = CDROM_REG0 & ~3; @@ -100,6 +105,7 @@ CESTER_TEST(raceNopAndGetLocP, test_instances, cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x98, ctrl0); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(5, response1[0]); @@ -128,6 +134,7 @@ CESTER_TEST(raceNopAndGetTD1, test_instance, CDROM_REG2 = 1; CDROM_REG1 = CDL_NOP; CDROM_REG1 = CDL_GETTD; + uint8_t ctrl0 = CDROM_REG0 & ~3; uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); @@ -148,17 +155,17 @@ CESTER_TEST(raceNopAndGetTD1, test_instance, cester_assert_uint_eq(0, response1[1]); cester_assert_uint_eq(2, response1[2]); cester_assert_uint_eq(3, responseSize1); + cester_assert_uint_eq(0x90, ctrl0); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_false(gotIRQ); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("Nop followed by GetTD1: ack in %ius\n", ackTime); IMASK = imask; ) - CESTER_TEST(raceGetTD1AndNop, test_instance, uint32_t imask = IMASK; @@ -176,6 +183,7 @@ CESTER_TEST(raceGetTD1AndNop, test_instance, CDROM_REG2 = 1; CDROM_REG1 = CDL_GETTD; CDROM_REG1 = CDL_NOP; + uint8_t ctrl0 = CDROM_REG0 & ~3; uint32_t ackTime = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); @@ -195,12 +203,108 @@ CESTER_TEST(raceGetTD1AndNop, test_instance, cester_assert_uint_eq(3, response1[0]); cester_assert_uint_eq(0x20, response1[1]); cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x90, ctrl0); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_false(gotIRQ); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); + ramsyscall_printf("GetTD1 followed by Nop: ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlSeekP2to80, test_instance, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x80, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + uint8_t ctrl0 = CDROM_REG0 & ~3; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + uint8_t ctrl2b = CDROM_REG0 & ~3; + + initializeTime(); + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint32_t timeout = 20000000; + int gotIRQ = waitCDRomIRQWithTimeout(&timeout); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(6, response3[0]); + cester_assert_uint_eq(0x10, response3[1]); + cester_assert_uint_eq(2, responseSize3); + cester_assert_uint_eq(0x98, ctrl0); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x98, ctrl2b); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_true(gotIRQ); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + ramsyscall_printf("SeekP from 00:02:00 to 80:00:00 with Nop in between: ack in %ius, ack2 in %ius, errored in %ius\n", ackTime, ackTime2, timeout); IMASK = imask; ) From add6d8c2e4a5477cb0f5cc0dabaa2544f365570d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 30 Dec 2022 11:09:33 -0800 Subject: [PATCH 119/185] Fixing test name. --- src/mips/tests/cdrom/race.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 28f6d49b9..b0717b7f5 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -214,7 +214,7 @@ CESTER_TEST(raceGetTD1AndNop, test_instance, IMASK = imask; ) -CESTER_TEST(cdlSeekP2to80, test_instance, +CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; From 2b6f1619c98fc2c5c5f4a6bddece5d87db109c68 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 30 Dec 2022 17:21:27 -0800 Subject: [PATCH 120/185] One more race. --- src/mips/tests/cdrom/race.c | 62 ++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index b0717b7f5..0885b5e2f 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -270,8 +270,7 @@ CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, uint8_t cause2b = CDROM_REG3_UC; initializeTime(); - uint32_t timeout = 20000000; - int gotIRQ = waitCDRomIRQWithTimeout(&timeout); + uint32_t errorTime = waitCDRomIRQ(); uint8_t cause3 = ackCDRomCause(); uint8_t ctrl5 = CDROM_REG0 & ~3; uint8_t response3[16]; @@ -299,12 +298,67 @@ CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_eq(0x38, ctrl5); cester_assert_uint_eq(0x18, ctrl6); - cester_assert_true(gotIRQ); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); cester_assert_uint_ge(ackTime2, 500); cester_assert_uint_lt(ackTime2, 7000); - ramsyscall_printf("SeekP from 00:02:00 to 80:00:00 with Nop in between: ack in %ius, ack2 in %ius, errored in %ius\n", ackTime, ackTime2, timeout); + ramsyscall_printf("SeekP from 00:02:00 to 80:00:00 with Nop in between: ack in %ius, ack2 in %ius, errored in %ius\n", ackTime, ackTime2, errorTime); IMASK = imask; ) + +CESTER_TEST(raceNopWaitAndNop, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + uint8_t ctrl0 = CDROM_REG0 & ~3; + + while (updateTime() < 50000); + uint8_t ctrl0b = CDROM_REG0 & ~3; + CDROM_REG1 = CDL_NOP; + + initializeTime(); + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0x98, ctrl0); + cester_assert_uint_eq(0x38, ctrl0b); + cester_assert_uint_eq(0xb8, ctrl1); + cester_assert_uint_eq(0x98, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + // This one really ought to be 0, but let's give some slack anyway. + cester_assert_uint_lt(ackTime, 150); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + ramsyscall_printf("Nop followed by Nop, ack in %ius, ack2 in %ius\n", ackTime, ackTime2); +) From 8615a4a36806c79b0985e8672068717728daf129 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 30 Dec 2022 21:23:37 -0800 Subject: [PATCH 121/185] Adding nop tests, tweaking a few more, and adding a few races. --- src/mips/tests/cdrom/cdlnop.c | 145 ++++++++++++++++++++++++++++++++ src/mips/tests/cdrom/cdlreads.c | 2 +- src/mips/tests/cdrom/cdlseekl.c | 8 +- src/mips/tests/cdrom/cdrom.c | 1 + src/mips/tests/cdrom/race.c | 78 ++++++++++++++++- 5 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 src/mips/tests/cdrom/cdlnop.c diff --git a/src/mips/tests/cdrom/cdlnop.c b/src/mips/tests/cdrom/cdlnop.c new file mode 100644 index 000000000..7b3197df4 --- /dev/null +++ b/src/mips/tests/cdrom/cdlnop.c @@ -0,0 +1,145 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(cdlNop, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + uint32_t imask = IMASK; + IMASK = imask | IRQ_CDROM; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic cdlNop, ack in %ius\n", ackTime); + + IMASK = imask; +) + +CESTER_TEST(cdlNopTooManyArgs, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + CDROM_REG0 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG2 = 0; + CDROM_REG1 = CDL_NOP; + + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(3, response1[0]); + cester_assert_uint_eq(0x20, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(errorTime, 500); + cester_assert_uint_lt(errorTime, 7000); + ramsyscall_printf("Basic cdlNop with too many args, errored in %ius\n", errorTime); + + IMASK = imask; +) + +CESTER_TEST(cdlNopBusyTime, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + uint32_t imask = IMASK; + IMASK = imask | IRQ_CDROM; + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + while (CDROM_REG0 & 0x80); + uint32_t busyTime = updateTime(); + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("Basic cdlNop, ack in %ius, busy flag was set for %ius, actual processing time %ius\n", ackTime, busyTime, ackTime - busyTime); + + IMASK = imask; +) + diff --git a/src/mips/tests/cdrom/cdlreads.c b/src/mips/tests/cdrom/cdlreads.c index a5c99cb0b..9ff32003e 100644 --- a/src/mips/tests/cdrom/cdlreads.c +++ b/src/mips/tests/cdrom/cdlreads.c @@ -811,7 +811,7 @@ CESTER_TEST(cdlReadS2xWithNop, test_instances, cester_assert_uint_eq(0xe0, cause5b); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); - cester_assert_uint_eq(0x18, ctrl2b); + cester_assert_uint_eq(0x98, ctrl2b); cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x18, ctrl4); cester_assert_uint_eq(0x38, ctrl5); diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c index 11d8157f0..d832a08e6 100644 --- a/src/mips/tests/cdrom/cdlseekl.c +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -287,7 +287,7 @@ CESTER_TEST(cdlSeekL2to71, test_instance, IMASK = imask; ) -CESTER_TEST(cdlSeekL2to80, test_instance, +CESTER_TEST(cdlSeekL2to85, test_instance, uint32_t imask = IMASK; IMASK = imask | IRQ_CDROM; @@ -304,7 +304,7 @@ CESTER_TEST(cdlSeekL2to80, test_instance, return; } - int setLocDone = setLoc(0x80, 0, 0); + int setLocDone = setLoc(0x85, 0, 0); if (!setLocDone) { cester_assert_true(setLocDone); return; @@ -355,8 +355,8 @@ CESTER_TEST(cdlSeekL2to80, test_instance, // disc. The failure can be faster than the previous test, because it won't // retry reading where there's clearly no information whatsoever. Will sometimes // fail in roughly 650ms, which is the seek time plus some minor retry. - cester_assert_uint_ge(errorTime, 600000); - ramsyscall_printf("Basic seekL from 00:02:00 to 80:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); + cester_assert_uint_ge(errorTime, 500000); + ramsyscall_printf("Basic seekL from 00:02:00 to 85:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 41cfddc11..5a7063cff 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -45,6 +45,7 @@ SOFTWARE. #include "cdlgettn.c" #include "cdlid.c" #include "cdlinit.c" +#include "cdlnop.c" #include "cdlreadn.c" #include "cdlreads.c" #include "cdlseekl.c" diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 0885b5e2f..fa38adfb7 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -308,6 +308,10 @@ CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, ) CESTER_TEST(raceNopWaitAndNop, test_instances, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -358,7 +362,77 @@ CESTER_TEST(raceNopWaitAndNop, test_instances, cester_assert_uint_eq(1, responseSize2); // This one really ought to be 0, but let's give some slack anyway. cester_assert_uint_lt(ackTime, 150); - cester_assert_uint_ge(ackTime2, 500); - cester_assert_uint_lt(ackTime2, 7000); + // The second ack's timing will be affected by the first ack's timing, + // so we can't really test it. ramsyscall_printf("Nop followed by Nop, ack in %ius, ack2 in %ius\n", ackTime, ackTime2); + + IMASK = imask; +) + +CESTER_TEST(nopQueue, test_instances, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + CDROM_REG0 = 0; + for (unsigned i = 0; i < 4; i++) { + initializeTime(); + CDROM_REG1 = CDL_NOP; + while (updateTime() < 50000); + } + + int gotIRQ = 0; + unsigned count = 0; + do { + initializeTime(); + uint32_t timeout = 50000; + gotIRQ = waitCDRomIRQWithTimeout(&timeout); + ackCDRomCause(); + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + } while (gotIRQ && ++count); + + cester_assert_uint_eq(2, count); + ramsyscall_printf("Nop command queue of %i\n", count); + + IMASK = imask; +) + +CESTER_TEST(nopQueueBusy, test_instances, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + uint8_t ctrl[2]; + CDROM_REG0 = 0; + for (unsigned i = 0; i < 2; i++) { + initializeTime(); + CDROM_REG1 = CDL_NOP; + while (updateTime() < 50000); + ctrl[i] = CDROM_REG0 & ~3; + } + + for (unsigned i = 0; i < 2; i++) { + waitCDRomIRQ(); + ackCDRomCause(); + uint8_t response[16]; + readResponse(response); + } + + cester_assert_uint_eq(0x38, ctrl[0]); + cester_assert_uint_eq(0xb8, ctrl[1]); + + IMASK = imask; ) From c471f65a64c97a3234825a2eb34ac9b4ff0d3f2a Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 31 Dec 2022 10:09:31 -0800 Subject: [PATCH 122/185] Derp. --- src/mips/tests/cdrom/cdlreadn.c | 10 +++++----- src/mips/tests/cdrom/cdlreads.c | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c index 9f7158a13..922eed1c7 100644 --- a/src/mips/tests/cdrom/cdlreadn.c +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -116,7 +116,7 @@ CESTER_TEST(cdlReadN1x, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -234,7 +234,7 @@ CESTER_TEST(cdlReadN1xwithDMA, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -348,7 +348,7 @@ CESTER_TEST(cdlReadN2x, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -476,7 +476,7 @@ CESTER_TEST(cdlReadN2xwithDMA, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -594,7 +594,7 @@ CESTER_TEST(cdlReadN2xRunaway, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); diff --git a/src/mips/tests/cdrom/cdlreads.c b/src/mips/tests/cdrom/cdlreads.c index 9ff32003e..cc7b3a8e5 100644 --- a/src/mips/tests/cdrom/cdlreads.c +++ b/src/mips/tests/cdrom/cdlreads.c @@ -116,7 +116,7 @@ CESTER_TEST(cdlReadS1x, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -234,7 +234,7 @@ CESTER_TEST(cdlReadS1xwithDMA, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -348,7 +348,7 @@ CESTER_TEST(cdlReadS2x, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -476,7 +476,7 @@ CESTER_TEST(cdlReadS2xwithDMA, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -594,7 +594,7 @@ CESTER_TEST(cdlReadS2xRunaway, test_instances, cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_ge(ackTime1, 500); @@ -825,7 +825,7 @@ CESTER_TEST(cdlReadS2xWithNop, test_instances, cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); - cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(0x22, response4[0]); cester_assert_uint_eq(1, responseSize4); cester_assert_uint_eq(2, response5[0]); From 47c3a9e475e33074a7efb1102a5731415af4f228 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 31 Dec 2022 10:09:41 -0800 Subject: [PATCH 123/185] Adding some reading tests. --- src/mips/tests/cdrom/cdrom.c | 1 + src/mips/tests/cdrom/reading.c | 239 +++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 src/mips/tests/cdrom/reading.c diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 5a7063cff..97cc30b44 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -55,3 +55,4 @@ SOFTWARE. #include "cdltest.c" #include "invalid.c" #include "race.c" +#include "reading.c" diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c new file mode 100644 index 000000000..02ecd0672 --- /dev/null +++ b/src/mips/tests/cdrom/reading.c @@ -0,0 +1,239 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(simpleReading, test_instances, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0x20, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + waitCDRomIRQ(); + ackCDRomCause(); + + initializeTime(); + while (updateTime() <= 500000); + + initializeTime(); + uint32_t time1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + + initializeTime(); + uint32_t time3 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time4 = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(1, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(0x22, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize3); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + ramsyscall_printf("Long read, ack then pause, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + + IMASK = imask; +) + +CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, + uint32_t imask = IMASK; + + IMASK = imask | IRQ_CDROM; + + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0x20, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + waitCDRomIRQ(); + ackCDRomCause(); + + initializeTime(); + while (updateTime() <= 500000); + uint8_t sector[2048]; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + + initializeTime(); + uint32_t time1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + + initializeTime(); + uint32_t time3 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time4 = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + // This bit will jitter + cester_assert_uint_eq(3, response1[0] & ~0x40); + cester_assert_uint_eq(0x80, response1[1]); + cester_assert_uint_eq(2, responseSize1); + cester_assert_uint_eq(0x23, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize3); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + ramsyscall_printf("Long read, pause then ack, error in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + + IMASK = imask; +) From 57e737e3e44a1a75532c8380326248e61748e989 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 1 Jan 2023 09:47:39 -0800 Subject: [PATCH 124/185] Adding a couple more tests, and cleaning up IMASK. --- src/mips/tests/cdrom/cdlgettd.c | 97 +----------------------- src/mips/tests/cdrom/cdlgettn.c | 12 --- src/mips/tests/cdrom/cdlid.c | 12 --- src/mips/tests/cdrom/cdlinit.c | 19 +---- src/mips/tests/cdrom/cdlnop.c | 16 ---- src/mips/tests/cdrom/cdlseekl.c | 30 -------- src/mips/tests/cdrom/cdlseekp.c | 30 -------- src/mips/tests/cdrom/cdlsetmode.c | 18 ----- src/mips/tests/cdrom/cdltest.c | 24 ------ src/mips/tests/cdrom/cdrom.c | 4 + src/mips/tests/cdrom/cester-hw.c | 31 +------- src/mips/tests/cdrom/invalid.c | 6 -- src/mips/tests/cdrom/race.c | 73 +++++++++--------- src/mips/tests/cdrom/reading.c | 119 +++++++++++++++++++++++++++--- 14 files changed, 155 insertions(+), 336 deletions(-) diff --git a/src/mips/tests/cdrom/cdlgettd.c b/src/mips/tests/cdrom/cdlgettd.c index 97756f492..3bf0bfdd2 100644 --- a/src/mips/tests/cdrom/cdlgettd.c +++ b/src/mips/tests/cdrom/cdlgettd.c @@ -27,10 +27,6 @@ SOFTWARE. // clang-format off CESTER_TEST(cdlGetTD0, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -63,15 +59,9 @@ CESTER_TEST(cdlGetTD0, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 0: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD1, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -104,16 +94,10 @@ CESTER_TEST(cdlGetTD1, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 1: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD2, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -146,16 +130,10 @@ CESTER_TEST(cdlGetTD2, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 2: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD3, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -188,15 +166,9 @@ CESTER_TEST(cdlGetTD3, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 3: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD4, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -229,15 +201,9 @@ CESTER_TEST(cdlGetTD4, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 4: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD5, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -270,15 +236,9 @@ CESTER_TEST(cdlGetTD5, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 5: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD6, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -311,15 +271,9 @@ CESTER_TEST(cdlGetTD6, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 6: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD12, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -352,15 +306,9 @@ CESTER_TEST(cdlGetTD12, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 12: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD25, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -393,15 +341,9 @@ CESTER_TEST(cdlGetTD25, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTD 25: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD26, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -433,15 +375,9 @@ CESTER_TEST(cdlGetTD26, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 26: errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD99, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -473,15 +409,9 @@ CESTER_TEST(cdlGetTD99, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 99: errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTDaa, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -513,15 +443,9 @@ CESTER_TEST(cdlGetTDaa, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD aa: errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD0a, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -553,15 +477,9 @@ CESTER_TEST(cdlGetTD0a, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 0a: errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTD1a, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -593,15 +511,9 @@ CESTER_TEST(cdlGetTD1a, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic getTD 1a: errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTDNoArgs, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -632,15 +544,9 @@ CESTER_TEST(cdlGetTDNoArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("No args getTD: errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTDTooManyArgs, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -673,6 +579,5 @@ CESTER_TEST(cdlGetTDTooManyArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Too many args getTD: errored in %ius\n", errorTime); - - IMASK = imask; ) + diff --git a/src/mips/tests/cdrom/cdlgettn.c b/src/mips/tests/cdrom/cdlgettn.c index 80ea04a2d..d876f37b1 100644 --- a/src/mips/tests/cdrom/cdlgettn.c +++ b/src/mips/tests/cdrom/cdlgettn.c @@ -27,10 +27,6 @@ SOFTWARE. // clang-format off CESTER_TEST(cdlGetTN, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -63,15 +59,9 @@ CESTER_TEST(cdlGetTN, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic getTN: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlGetTNWithArgs, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -107,6 +97,4 @@ CESTER_TEST(cdlGetTNWithArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Too many args getTN: errored in %ius\n", errorTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlid.c b/src/mips/tests/cdrom/cdlid.c index 9d4ce0e7b..0598defbe 100644 --- a/src/mips/tests/cdrom/cdlid.c +++ b/src/mips/tests/cdrom/cdlid.c @@ -35,10 +35,6 @@ CESTER_TEST(cdlId, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG1 = CDL_GETID; @@ -77,8 +73,6 @@ CESTER_TEST(cdlId, test_instance, ramsyscall_printf("Full response: %02x %02x %02x %02x %02x %02x %02x %02x\n", response2[0], response2[1], response2[2], response2[3], response2[4], response2[5], response2[6], response2[7]); - - IMASK = imask; ) CESTER_TEST(cdlIdTooManyArgs, test_instance, @@ -90,10 +84,6 @@ CESTER_TEST(cdlIdTooManyArgs, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = 0; CDROM_REG2 = 0; @@ -120,7 +110,5 @@ CESTER_TEST(cdlIdTooManyArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic cdlId with too many args, errored in %ius\n", errorTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlinit.c b/src/mips/tests/cdrom/cdlinit.c index d071de242..1d3a3daad 100644 --- a/src/mips/tests/cdrom/cdlinit.c +++ b/src/mips/tests/cdrom/cdlinit.c @@ -29,10 +29,6 @@ SOFTWARE. CESTER_TEST(cdlInit, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 1; CDROM_REG3 = 0x1f; CDROM_REG0 = 1; @@ -78,17 +74,11 @@ CESTER_TEST(cdlInit, test_instance, cester_assert_uint_ge(completeTime, 50000); cester_assert_uint_lt(completeTime, 150000); ramsyscall_printf("Basic initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; ) CESTER_TEST(cdlInitDelayed, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 1; CDROM_REG3 = 0x1f; CDROM_REG0 = 1; @@ -138,17 +128,11 @@ CESTER_TEST(cdlInitDelayed, test_instance, cester_assert_uint_ge(completeTime, 100); cester_assert_uint_lt(completeTime, 1000); ramsyscall_printf("Delayed initialization: CD-Rom controller initialized, ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; ) CESTER_TEST(cdlInitWithArgs, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 1; CDROM_REG3 = 0x1f; CDROM_REG0 = 1; @@ -201,7 +185,6 @@ CESTER_TEST(cdlInitWithArgs, test_instance, cester_assert_uint_lt(ackTime, 3500); ramsyscall_printf("Initialization with args: CD-Rom controller errored, error in %ius\n", errorTime); ramsyscall_printf("Initialization with args: requested status, ack in %ius\n", ackTime); - - IMASK = imask; ) + diff --git a/src/mips/tests/cdrom/cdlnop.c b/src/mips/tests/cdrom/cdlnop.c index 7b3197df4..21bb84c35 100644 --- a/src/mips/tests/cdrom/cdlnop.c +++ b/src/mips/tests/cdrom/cdlnop.c @@ -33,9 +33,6 @@ CESTER_TEST(cdlNop, test_instance, return; } - uint32_t imask = IMASK; - IMASK = imask | IRQ_CDROM; - initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; @@ -58,8 +55,6 @@ CESTER_TEST(cdlNop, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic cdlNop, ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlNopTooManyArgs, test_instance, @@ -71,10 +66,6 @@ CESTER_TEST(cdlNopTooManyArgs, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = 0; CDROM_REG2 = 0; @@ -101,8 +92,6 @@ CESTER_TEST(cdlNopTooManyArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic cdlNop with too many args, errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlNopBusyTime, test_instance, @@ -112,9 +101,6 @@ CESTER_TEST(cdlNopBusyTime, test_instance, return; } - uint32_t imask = IMASK; - IMASK = imask | IRQ_CDROM; - initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; @@ -139,7 +125,5 @@ CESTER_TEST(cdlNopBusyTime, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic cdlNop, ack in %ius, busy flag was set for %ius, actual processing time %ius\n", ackTime, busyTime, ackTime - busyTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlseekl.c b/src/mips/tests/cdrom/cdlseekl.c index d832a08e6..1315bf411 100644 --- a/src/mips/tests/cdrom/cdlseekl.c +++ b/src/mips/tests/cdrom/cdlseekl.c @@ -27,10 +27,6 @@ SOFTWARE. // clang-format off CESTER_TEST(cdlSeekL, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -87,15 +83,9 @@ CESTER_TEST(cdlSeekL, test_instance, // already around the right place, so it's mostly a no-op to seek there, but // can vary a lot between 2ms and 500ms as the head is moving and re-aligning. ramsyscall_printf("Basic seekL to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekLwithArgs, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -139,15 +129,9 @@ CESTER_TEST(cdlSeekLwithArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Too many args seekL, errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekL2to4, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -210,15 +194,9 @@ CESTER_TEST(cdlSeekL2to4, test_instance, // a lot depending on the status of the drive, but it should probably be // at least 120ms, and more likely 170ms. ramsyscall_printf("Basic seekL from 00:02:00 to 00:04:00: ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekL2to71, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -283,15 +261,9 @@ CESTER_TEST(cdlSeekL2to71, test_instance, // keep retrying reading data where there's none. Roughly 4s. cester_assert_uint_ge(errorTime, 4000000); ramsyscall_printf("Basic seekL from 00:02:00 to 71:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekL2to85, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -357,6 +329,4 @@ CESTER_TEST(cdlSeekL2to85, test_instance, // fail in roughly 650ms, which is the seek time plus some minor retry. cester_assert_uint_ge(errorTime, 500000); ramsyscall_printf("Basic seekL from 00:02:00 to 85:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 3e948118a..3126918a8 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -27,10 +27,6 @@ SOFTWARE. // clang-format off CESTER_TEST(cdlSeekP, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -87,15 +83,9 @@ CESTER_TEST(cdlSeekP, test_instance, // already around the right place, so it's mostly a no-op to seek there, but // can vary a lot between 2ms and 500ms as the head is moving and re-aligning. ramsyscall_printf("Basic seekP to 00:02:00: ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekPwithArgs, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -139,15 +129,9 @@ CESTER_TEST(cdlSeekPwithArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Too many args seekP, errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekP2to4, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -210,15 +194,9 @@ CESTER_TEST(cdlSeekP2to4, test_instance, // a lot depending on the status of the drive, but it should probably be // at least 100ms, and more likely 150ms. ramsyscall_printf("Basic seekP from 00:02:00 to 00:04:00: ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekP2to71, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -280,15 +258,9 @@ CESTER_TEST(cdlSeekP2to71, test_instance, // This is a pretty long distance seek, which will take at least a full second. cester_assert_uint_ge(completeTime, 1000000); ramsyscall_printf("Basic seekP from 00:02:00 to 71:00:00: ack in %ius, complete in %ius\n", ackTime, completeTime); - - IMASK = imask; ) CESTER_TEST(cdlSeekP2to80, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -354,6 +326,4 @@ CESTER_TEST(cdlSeekP2to80, test_instance, // fail in roughly 650ms, which is the seek time plus some minor retry. cester_assert_uint_ge(errorTime, 600000); ramsyscall_printf("Basic seekP from 00:02:00 to 80:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdlsetmode.c b/src/mips/tests/cdrom/cdlsetmode.c index bf8b5f1e4..90406a0ab 100644 --- a/src/mips/tests/cdrom/cdlsetmode.c +++ b/src/mips/tests/cdrom/cdlsetmode.c @@ -27,10 +27,6 @@ SOFTWARE. // clang-format off CESTER_TEST(cdlSetMode, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -62,15 +58,9 @@ CESTER_TEST(cdlSetMode, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic setMode: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(cdlSetModeWithoutArgs, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -102,15 +92,9 @@ CESTER_TEST(cdlSetModeWithoutArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("No args setMode: errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlSetModeWithTooManyArgs, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -146,6 +130,4 @@ CESTER_TEST(cdlSetModeWithTooManyArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("No args setMode: errored in %ius\n", errorTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdltest.c b/src/mips/tests/cdrom/cdltest.c index 868a00170..7d0b7e080 100644 --- a/src/mips/tests/cdrom/cdltest.c +++ b/src/mips/tests/cdrom/cdltest.c @@ -35,10 +35,6 @@ CESTER_TEST(cdlTestNoArg, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG1 = CDL_TEST; @@ -61,8 +57,6 @@ CESTER_TEST(cdlTestNoArg, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic cdlTest with no args, errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlTest20, test_instance, @@ -74,10 +68,6 @@ CESTER_TEST(cdlTest20, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = 0x20; CDROM_REG1 = CDL_TEST; @@ -99,8 +89,6 @@ CESTER_TEST(cdlTest20, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic cdlTest with arg = 0x20, ack in %ius, response = %02x %02x %02x %02x\n", ackTime, response1[0], response1[1], response1[2], response1[3]); - - IMASK = imask; ) CESTER_TEST(cdlTest20ExtraArgs, test_instance, @@ -112,10 +100,6 @@ CESTER_TEST(cdlTest20ExtraArgs, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = 0x20; CDROM_REG2 = 0x00; @@ -140,8 +124,6 @@ CESTER_TEST(cdlTest20ExtraArgs, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Basic cdlTest with arg = 0x20, 0x00, errored in %ius\n", errorTime); - - IMASK = imask; ) CESTER_TEST(cdlTestff, test_instance, @@ -153,10 +135,6 @@ CESTER_TEST(cdlTestff, test_instance, initializeTime(); - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = 0xff; CDROM_REG1 = CDL_TEST; @@ -180,6 +158,4 @@ CESTER_TEST(cdlTestff, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Basic cdlTest with arg = 0xff, errored in %ius\n", ackTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 97cc30b44..cd5162b79 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -39,6 +39,7 @@ SOFTWARE. #include "cester-hw.c" +#if 1 #include "cdlgetlocl.c" #include "cdlgetlocp.c" #include "cdlgettd.c" @@ -56,3 +57,6 @@ SOFTWARE. #include "invalid.c" #include "race.c" #include "reading.c" +#else +#include "race.c" +#endif diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index bd88ca18c..fb80c1989 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -36,6 +36,7 @@ CESTER_BODY( static uint16_t s_oldMode = 0; static uint32_t s_lastHSyncCounter = 0; static uint32_t s_currentTime = 0; + static uint32_t s_oldIMASK = 0; static const unsigned US_PER_HBLANK = 64; struct LocPResult { @@ -131,11 +132,7 @@ CESTER_BODY( } int setMode(uint8_t mode) { - uint32_t imask = IMASK; uint8_t cause; - - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = mode; CDROM_REG1 = CDL_SETMODE; @@ -143,17 +140,12 @@ CESTER_BODY( cause = ackCDRomCause(); CDROM_REG1; if (cause != 3) return 0; - - IMASK = imask; return 1; } static inline int resetCDRom() { - uint32_t imask = IMASK; uint8_t cause; - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 1; CDROM_REG3 = 0x1f; CDROM_REG0 = 1; @@ -172,16 +164,12 @@ CESTER_BODY( initializeTime(); // wait 10ms for things to settle while (updateTime() < 10000); - IMASK = imask; return setMode(0); } static int setLoc(uint8_t minute, uint8_t second, uint8_t frame) { - uint32_t imask = IMASK; uint8_t cause; - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = minute; CDROM_REG2 = second; @@ -192,16 +180,12 @@ CESTER_BODY( CDROM_REG1; if (cause != 3) return 0; - IMASK = imask; return 1; } static int seekPTo(uint8_t minute, uint8_t second, uint8_t frame) { - uint32_t imask = IMASK; uint8_t cause; - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = minute; CDROM_REG2 = second; @@ -222,17 +206,12 @@ CESTER_BODY( cause = ackCDRomCause(); CDROM_REG1; if (cause != 2) return 0; - - IMASK = imask; return 1; } static int seekLTo(uint8_t minute, uint8_t second, uint8_t frame) { - uint32_t imask = IMASK; uint8_t cause; - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG2 = minute; CDROM_REG2 = second; @@ -254,23 +233,18 @@ CESTER_BODY( CDROM_REG1; if (cause != 2) return 0; - IMASK = imask; return 1; } uint8_t getCtrl() { - uint32_t imask = IMASK; uint8_t cause; - IMASK = imask | IRQ_CDROM; - CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; waitCDRomIRQ(); ackCDRomCause(); uint8_t ctrl = CDROM_REG1; - IMASK = imask; return ctrl; } ) @@ -281,9 +255,12 @@ CESTER_BEFORE_ALL(cpu_tests, COUNTERS[1].mode = 0x0100; SBUS_DEV5_CTRL = 0x20943; SBUS_COM_CTRL = 0x132c; + s_oldIMASK = IMASK; + IMASK = IRQ_CDROM; ) CESTER_AFTER_ALL(cpu_tests, + IMASK = s_oldIMASK; COUNTERS[1].mode = s_oldMode; if (s_interruptsWereEnabled) leaveCriticalSection(); ) diff --git a/src/mips/tests/cdrom/invalid.c b/src/mips/tests/cdrom/invalid.c index 47df576bc..aa8362396 100644 --- a/src/mips/tests/cdrom/invalid.c +++ b/src/mips/tests/cdrom/invalid.c @@ -27,10 +27,6 @@ SOFTWARE. // clang-format off CESTER_TEST(invalid0, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -62,6 +58,4 @@ CESTER_TEST(invalid0, test_instance, cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); ramsyscall_printf("Invalid command 0: errored in %ius\n", errorTime); - - IMASK = imask; ) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index fa38adfb7..7f6beadff 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -118,10 +118,6 @@ CESTER_TEST(raceNopAndGetLocP, test_instances, ) CESTER_TEST(raceNopAndGetTD1, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -162,15 +158,9 @@ CESTER_TEST(raceNopAndGetTD1, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("Nop followed by GetTD1: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(raceGetTD1AndNop, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -210,15 +200,9 @@ CESTER_TEST(raceGetTD1AndNop, test_instance, cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); ramsyscall_printf("GetTD1 followed by Nop: ack in %ius\n", ackTime); - - IMASK = imask; ) CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -303,15 +287,9 @@ CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, cester_assert_uint_ge(ackTime2, 500); cester_assert_uint_lt(ackTime2, 7000); ramsyscall_printf("SeekP from 00:02:00 to 80:00:00 with Nop in between: ack in %ius, ack2 in %ius, errored in %ius\n", ackTime, ackTime2, errorTime); - - IMASK = imask; ) CESTER_TEST(raceNopWaitAndNop, test_instances, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -365,15 +343,9 @@ CESTER_TEST(raceNopWaitAndNop, test_instances, // The second ack's timing will be affected by the first ack's timing, // so we can't really test it. ramsyscall_printf("Nop followed by Nop, ack in %ius, ack2 in %ius\n", ackTime, ackTime2); - - IMASK = imask; ) CESTER_TEST(nopQueue, test_instances, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -400,15 +372,9 @@ CESTER_TEST(nopQueue, test_instances, cester_assert_uint_eq(2, count); ramsyscall_printf("Nop command queue of %i\n", count); - - IMASK = imask; ) CESTER_TEST(nopQueueBusy, test_instances, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -433,6 +399,43 @@ CESTER_TEST(nopQueueBusy, test_instances, cester_assert_uint_eq(0x38, ctrl[0]); cester_assert_uint_eq(0xb8, ctrl[1]); +) - IMASK = imask; +CESTER_TEST(readResponseBeforeAck, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + + while (CDROM_REG0 & 0x80); + CDROM_REG1 = CDL_NOP; + + while (updateTime() < 50000); + + waitCDRomIRQ(); + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t cause1 = ackCDRomCause(); + waitCDRomIRQ(); + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t cause2 = ackCDRomCause(); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(5, response1[0]); + cester_assert_uint_eq(8, responseSize1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); ) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 02ecd0672..1510aa574 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -27,10 +27,6 @@ SOFTWARE. // clang-format off CESTER_TEST(simpleReading, test_instances, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -125,15 +121,9 @@ CESTER_TEST(simpleReading, test_instances, cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); ramsyscall_printf("Long read, ack then pause, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); - - IMASK = imask; ) CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, - uint32_t imask = IMASK; - - IMASK = imask | IRQ_CDROM; - int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -159,7 +149,6 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, initializeTime(); while (updateTime() <= 500000); - uint8_t sector[2048]; CDROM_REG0 = 0; CDROM_REG1 = CDL_PAUSE; @@ -234,6 +223,112 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); ramsyscall_printf("Long read, pause then ack, error in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); +) + +CESTER_TEST(simpleReadingNopQuery, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0x20, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + waitCDRomIRQ(); + ackCDRomCause(); + + initializeTime(); + + for (unsigned i = 0; i < 100; i++) { + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + waitCDRomIRQ(); + ackCDRomCause(); + uint8_t response[16]; + readResponse(response); + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + + initializeTime(); + uint32_t time1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + + initializeTime(); + uint32_t time3 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time4 = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; - IMASK = imask; + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize3); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + ramsyscall_printf("Long read, nop then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); ) From 3d54b2e72221494b76b23d864fecad7bfa18996d Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 1 Jan 2023 10:26:32 -0800 Subject: [PATCH 125/185] Adding another sanity check. --- src/mips/tests/cdrom/race.c | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 7f6beadff..2508e7f2a 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -439,3 +439,42 @@ CESTER_TEST(readResponseBeforeAck, test_instances, cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); ) + +CESTER_TEST(ackBeforeReadResponse, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + + while (CDROM_REG0 & 0x80); + CDROM_REG1 = CDL_NOP; + + while (updateTime() < 50000); + + waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(5, response1[0]); + cester_assert_uint_eq(8, responseSize1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); +) From 896cf1e79b99664bead2e89d1a4670e5a8c0f570 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 1 Jan 2023 10:46:41 -0800 Subject: [PATCH 126/185] And some more for completeness. --- src/mips/tests/cdrom/race.c | 105 ++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 2508e7f2a..91f8f52ae 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -427,17 +427,24 @@ CESTER_TEST(readResponseBeforeAck, test_instances, uint8_t response1[16]; uint8_t responseSize1 = readResponse(response1); uint8_t cause1 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; waitCDRomIRQ(); uint8_t response2[16]; uint8_t responseSize2 = readResponse(response2); uint8_t cause2 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(5, response1[0]); cester_assert_uint_eq(8, responseSize1); cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause2b); cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); + ) CESTER_TEST(ackBeforeReadResponse, test_instances, @@ -464,17 +471,115 @@ CESTER_TEST(ackBeforeReadResponse, test_instances, waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; uint8_t response1[16]; uint8_t responseSize1 = readResponse(response1); waitCDRomIRQ(); uint8_t cause2 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; uint8_t response2[16]; uint8_t responseSize2 = readResponse(response2); cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(5, response1[0]); cester_assert_uint_eq(8, responseSize1); cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + +) + +CESTER_TEST(mixedReadAndAck1, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + + while (CDROM_REG0 & 0x80); + CDROM_REG1 = CDL_NOP; + + while (updateTime() < 50000); + + waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + waitCDRomIRQ(); + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t cause2 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(5, response1[0]); + cester_assert_uint_eq(8, responseSize1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + +) + +CESTER_TEST(mixedReadAndAck2, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + + while (CDROM_REG0 & 0x80); + CDROM_REG1 = CDL_NOP; + + while (updateTime() < 50000); + + waitCDRomIRQ(); + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t cause1 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(5, response1[0]); + cester_assert_uint_eq(8, responseSize1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause2b); cester_assert_uint_eq(2, response2[0]); cester_assert_uint_eq(1, responseSize2); ) From 70550188ed140ae8dc8bfe3ffb2e51184b13bfc0 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 1 Jan 2023 21:38:49 -0800 Subject: [PATCH 127/185] Adding a couple more reading tests. --- src/mips/tests/cdrom/reading.c | 174 ++++++++++++++++++++++++++++++++- 1 file changed, 173 insertions(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 1510aa574..493ba9f4e 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -39,6 +39,177 @@ CESTER_TEST(simpleReading, test_instances, return; } + int setLocDone = setLoc(0x20, 2, 0); + + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint8_t response[16]; + waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + readResponse(response); + + uint32_t sectorData[100]; + uint8_t causes[100]; + + __builtin_memset(sectorData, 0, sizeof(sectorData)); + __builtin_memset(causes, 0, sizeof(causes)); + + for (unsigned i = 0; i < 100; i++) { + waitCDRomIRQ(); + uint8_t cause = ackCDRomCause(); + causes[i] = cause; + readResponse(response); + if (cause != 1) break; + + uint8_t sector[2048]; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + uint32_t dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x00880000; + DICR = dicr; + DPCR |= 0x8000; + DMA_CTRL[DMA_CDROM].MADR = (uintptr_t)sector; + DMA_CTRL[DMA_CDROM].BCR = (2048 >> 2) | 0x10000; + DMA_CTRL[DMA_CDROM].CHCR = 0x11000000; + + while ((DMA_CTRL[DMA_CDROM].CHCR & 0x01000000) != 0); + dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x88000000; + DICR = dicr; + CDROM_REG3 = 0; + + uint32_t *sector32 = (uint32_t *)sector; + sectorData[i] = sector32[0]; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + readResponse(response); + waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + readResponse(response); + + uint32_t start = 20 * 60 * 75; + for (unsigned i = 0; i < 100; i++) { + cester_assert_uint_eq(start + i, sectorData[i]); + cester_assert_uint_eq(1, causes[i]); + } + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(2, cause3); +) + +CESTER_TEST(setLocDuringSimpleReading, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0x20, 2, 0); + + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint8_t response[16]; + waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + readResponse(response); + + uint32_t sectorData[100]; + uint8_t causes[100]; + + __builtin_memset(sectorData, 0, sizeof(sectorData)); + __builtin_memset(causes, 0, sizeof(causes)); + + for (unsigned i = 0; i < 100; i++) { + waitCDRomIRQ(); + uint8_t cause = ackCDRomCause(); + causes[i] = cause; + readResponse(response); + if (cause != 1) break; + + uint8_t sector[2048]; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + uint32_t dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x00880000; + DICR = dicr; + DPCR |= 0x8000; + DMA_CTRL[DMA_CDROM].MADR = (uintptr_t)sector; + DMA_CTRL[DMA_CDROM].BCR = (2048 >> 2) | 0x10000; + DMA_CTRL[DMA_CDROM].CHCR = 0x11000000; + + while ((DMA_CTRL[DMA_CDROM].CHCR & 0x01000000) != 0); + dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x88000000; + DICR = dicr; + CDROM_REG3 = 0; + + uint32_t *sector32 = (uint32_t *)sector; + sectorData[i] = sector32[0]; + + if (i == 50) setLocDone = setLoc(0x20, 2, 0); + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + readResponse(response); + waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + readResponse(response); + + uint32_t start = 20 * 60 * 75; + for (unsigned i = 0; i < 100; i++) { + cester_assert_uint_eq(start + i, sectorData[i]); + cester_assert_uint_eq(1, causes[i]); + } + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(2, cause3); + cester_assert_true(setLocDone); +) + +CESTER_TEST(simpleReadingWithoutAck, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + int setLocDone = setLoc(0x20, 0, 0); if (!setLocDone) { cester_assert_true(setLocDone); @@ -213,7 +384,8 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, cester_assert_uint_eq(0x38, ctrl7); cester_assert_uint_eq(0x18, ctrl8); // This bit will jitter - cester_assert_uint_eq(3, response1[0] & ~0x40); + uint8_t response1_0 = response1[0] & ~0x40; + cester_assert_uint_eq(3, response1_0); cester_assert_uint_eq(0x80, response1[1]); cester_assert_uint_eq(2, responseSize1); cester_assert_uint_eq(0x23, response2[0]); From f1c2ffed8e4802acc4a9990687907d3140c86ccb Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 1 Jan 2023 21:59:03 -0800 Subject: [PATCH 128/185] Adding memory usage caveat. --- src/mips/tests/cdrom/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index a2653501a..e57385987 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -12,6 +12,8 @@ This will emit a `test.cue` file, and multiple corresponding tracks. The data tr The tests are written in C, and are compiled using the [MIPS GCC toolchain](../../psyqo/GETTING_STARTED.md#the-toolchain). The tests are compiled using the `make` command, and the resulting binary needs to be run on systems that have an ANSI console connected. +One important caveat of the test framework is it'll allocate memory for failed tests, and the memory allocator is very rudimentary. This means that if too many tests fail, the system will run out of memory and crash. Check the file `cdrom.c` to disable portions of tests and work incrementally towards a working emulator. + The tests are checking two things: proper results from the CDRom controller, and approximate timings. The former are exact value checks, and will always reproduce properly on the real hardware. The latter are approximate value checks, and will usually only reproduce properly on the real hardware if the CD is inserted in the drive, the lid is closed, and the drive has been settled for a few seconds, but may still be flaky on the real hardware. The tests are currently being run on a 9001 machine for its real hardware routine checks, with occasional tests being run on a wider range of hardware. From 4ad707cf8587a21284ba5c33ec4abbebd9bb09ce Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 1 Jan 2023 22:58:28 -0800 Subject: [PATCH 129/185] Adding a couple more seek tests. --- src/mips/tests/cdrom/cdlseekp.c | 158 +++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 3 deletions(-) diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 3126918a8..9b4c3025f 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -260,7 +260,7 @@ CESTER_TEST(cdlSeekP2to71, test_instance, ramsyscall_printf("Basic seekP from 00:02:00 to 71:00:00: ack in %ius, complete in %ius\n", ackTime, completeTime); ) -CESTER_TEST(cdlSeekP2to80, test_instance, +CESTER_TEST(cdlSeekP2to85, test_instance, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -273,7 +273,7 @@ CESTER_TEST(cdlSeekP2to80, test_instance, return; } - int setLocDone = setLoc(0x80, 0, 0); + int setLocDone = setLoc(0x85, 0, 0); if (!setLocDone) { cester_assert_true(setLocDone); return; @@ -325,5 +325,157 @@ CESTER_TEST(cdlSeekP2to80, test_instance, // retry reading where there's clearly no information whatsoever. Will sometimes // fail in roughly 650ms, which is the seek time plus some minor retry. cester_assert_uint_ge(errorTime, 600000); - ramsyscall_printf("Basic seekP from 00:02:00 to 80:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); + ramsyscall_printf("Basic seekP from 00:02:00 to 85:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); +) + +CESTER_TEST(cdlSeekP2to85AndNop, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x85, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + + while (CDROM_REG0 & 0x85); + CDROM_REG1 = CDL_NOP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause1b = ackCDRomCause(); + uint8_t ctrl1b = CDROM_REG0 & ~3; + uint8_t response1b[16]; + uint8_t responseSize1b = readResponse(response1b); + uint8_t ctrl2b = CDROM_REG0 & ~3; + + initializeTime(); + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(3, cause1b); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response1b[0]); + cester_assert_uint_eq(1, responseSize1b); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(0x10, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_eq(0xb8, ctrl1); + cester_assert_uint_eq(0x38, ctrl1b); + cester_assert_uint_eq(0x98, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + cester_assert_uint_ge(errorTime, 600000); + ramsyscall_printf("Basic seekP with Nop from 00:02:00 to 85:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); +) + +CESTER_TEST(cdlSeekP2to85AndDelayedNop, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x85, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + + while (updateTime() < 50000); + CDROM_REG1 = CDL_NOP; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause1b = ackCDRomCause(); + uint8_t ctrl1b = CDROM_REG0 & ~3; + uint8_t response1b[16]; + uint8_t responseSize1b = readResponse(response1b); + uint8_t ctrl2b = CDROM_REG0 & ~3; + + initializeTime(); + uint32_t errorTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(3, cause1b); + cester_assert_uint_eq(5, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x42, response1b[0]); + cester_assert_uint_eq(1, responseSize1b); + cester_assert_uint_eq(6, response2[0]); + cester_assert_uint_eq(16, response2[1]); + cester_assert_uint_eq(2, responseSize2); + cester_assert_uint_eq(0xb8, ctrl1); + cester_assert_uint_eq(0x38, ctrl1b); + cester_assert_uint_eq(0x98, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_ge(errorTime, 600000); + ramsyscall_printf("Basic seekP with delayed Nop from 00:02:00 to 85:00:00: ack in %ius, errored in %ius\n", ackTime, errorTime); ) From 956f3abbe5a86b560dc964f76da1301e35f86b01 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 1 Jan 2023 23:04:31 -0800 Subject: [PATCH 130/185] More details. --- src/mips/tests/cdrom/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index e57385987..d85e019ec 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -12,7 +12,7 @@ This will emit a `test.cue` file, and multiple corresponding tracks. The data tr The tests are written in C, and are compiled using the [MIPS GCC toolchain](../../psyqo/GETTING_STARTED.md#the-toolchain). The tests are compiled using the `make` command, and the resulting binary needs to be run on systems that have an ANSI console connected. -One important caveat of the test framework is it'll allocate memory for failed tests, and the memory allocator is very rudimentary. This means that if too many tests fail, the system will run out of memory and crash. Check the file `cdrom.c` to disable portions of tests and work incrementally towards a working emulator. +One important caveat of the test framework is it'll allocate memory for failed tests, and the memory allocator is very rudimentary. This means that if too many tests fail, the system will run out of memory and crash. Check the file `cdrom.c` to disable portions of tests and work incrementally towards a working emulator. In order to further disable some tests, replace the corresponding `CESTER_TEST` keyword with `CESTER_SKIP_TEST`. The tests are checking two things: proper results from the CDRom controller, and approximate timings. The former are exact value checks, and will always reproduce properly on the real hardware. The latter are approximate value checks, and will usually only reproduce properly on the real hardware if the CD is inserted in the drive, the lid is closed, and the drive has been settled for a few seconds, but may still be flaky on the real hardware. From 0352524ecfedd892d9266c298baab38918c7ddc5 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 2 Jan 2023 09:37:59 -0800 Subject: [PATCH 131/185] Adding misc tests. --- src/mips/tests/cdrom/cdrom.c | 5 +- src/mips/tests/cdrom/cester-hw.c | 5 ++ src/mips/tests/cdrom/misc.c | 90 ++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/mips/tests/cdrom/misc.c diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index cd5162b79..e39c2b85d 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -39,7 +39,7 @@ SOFTWARE. #include "cester-hw.c" -#if 1 +#if 0 #include "cdlgetlocl.c" #include "cdlgetlocp.c" #include "cdlgettd.c" @@ -55,8 +55,9 @@ SOFTWARE. #include "cdlsetmode.c" #include "cdltest.c" #include "invalid.c" +#include "misc.c" #include "race.c" #include "reading.c" #else -#include "race.c" +#include "misc.c" #endif diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index fb80c1989..5563b238e 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -68,6 +68,11 @@ CESTER_BODY( return responseSize; } + static uint8_t discardResponse() { + uint8_t response[16]; + return readResponse(response); + } + static inline void initializeTime() { while (1) { uint32_t init = COUNTERS[1].value; diff --git a/src/mips/tests/cdrom/misc.c b/src/mips/tests/cdrom/misc.c new file mode 100644 index 000000000..11fbd7e80 --- /dev/null +++ b/src/mips/tests/cdrom/misc.c @@ -0,0 +1,90 @@ +/* + +MIT License + +Copyright (c) 2022 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +// These tests cannot be easily automated. + +CESTER_SKIP_TEST(waitForDoor, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0x70, 0x19, 0x73); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + ramsyscall_printf("Waiting for door to open...\n"); + + initializeTime(); + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x16, response[0]); + cester_assert_uint_eq(8, response[1]); + cester_assert_uint_eq(2, responseSize); +) + +CESTER_SKIP_TEST(doorOpenedOrMissingDisc, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETLOCP; + + initializeTime(); + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response[16]; + uint8_t responseSize = readResponse(response); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x11, response[0]); + cester_assert_uint_eq(0x80, response[1]); + cester_assert_uint_eq(2, responseSize); +) From 4baf2f18d2fe4512ea32b5ceabdac9d880216a82 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 2 Jan 2023 10:12:54 -0800 Subject: [PATCH 132/185] Renaming interrupts to schedules, and adding one more. --- src/core/cdrom.cc | 17 ++++++---- src/core/cdrom.h | 7 +++-- src/core/mdec.cc | 4 +-- src/core/mdec.h | 4 +-- src/core/psxdma.h | 10 +++--- src/core/r3000a.cc | 60 +++++++++++++++++++----------------- src/core/r3000a.h | 50 +++++++++++++++++------------- src/core/sio.cc | 4 +-- src/core/sio.h | 4 +-- src/core/sio1.cc | 4 +-- src/core/sio1.h | 6 ++-- src/core/sstate.cc | 4 +-- src/core/sstate.h | 8 ++--- src/gui/gui.cc | 11 +++---- src/gui/widgets/registers.cc | 2 +- 15 files changed, 105 insertions(+), 90 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index b7aa224c4..60d163df1 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -112,7 +112,7 @@ class CDRomImpl final : public PCSX::CDRom { m_realtime = false; } - void interrupt() override { + void fifoScheduledCallback() override { if (m_errorArgumentsCount) { m_errorArgumentsCount = false; m_cause = Cause::Error; @@ -137,7 +137,9 @@ class CDRomImpl final : public PCSX::CDRom { } } - void readInterrupt() override { + void commandsScheduledCallback() override {} + + void readScheduledCallback() override { static const std::chrono::nanoseconds c_retryDelay = 50us; const bool debug = PCSX::g_emulator->settings.get() .get(); @@ -223,20 +225,23 @@ class CDRomImpl final : public PCSX::CDRom { } } - void dmaInterrupt() override { + void scheduleDmaCallback() override { if (HW_DMA3_CHCR & SWAP_LE32(0x01000000)) { HW_DMA3_CHCR &= SWAP_LE32(~0x01000000); DMA_INTERRUPT<3>(); } } - void schedule(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDR, cycles); } + void scheduleFifo(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDRFIFO, cycles); } + void scheduleFifo(std::chrono::nanoseconds delay) { schedule(PCSX::psxRegisters::durationToCycles(delay)); } + + void schedule(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDRCOMMANDS, cycles); } void schedule(std::chrono::nanoseconds delay) { schedule(PCSX::psxRegisters::durationToCycles(delay)); } - void scheduleRead(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDREAD, cycles); } + void scheduleRead(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDREAD, cycles); } void scheduleRead(std::chrono::nanoseconds delay) { scheduleRead(PCSX::psxRegisters::durationToCycles(delay)); } - void scheduleDMA(uint32_t cycles) { PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_CDRDMA, cycles); } + void scheduleDMA(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDRDMA, cycles); } void scheduleDMA(std::chrono::nanoseconds delay) { scheduleDMA(PCSX::psxRegisters::durationToCycles(delay)); } void triggerIRQ() { diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 641897238..9d4016142 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -84,9 +84,10 @@ class CDRom { virtual void reset() = 0; - virtual void interrupt() = 0; - virtual void readInterrupt() = 0; - virtual void dmaInterrupt() = 0; + virtual void fifoScheduledCallback() = 0; + virtual void commandsScheduledCallback() = 0; + virtual void readScheduledCallback() = 0; + virtual void scheduleDmaCallback() = 0; virtual uint8_t read0() = 0; virtual uint8_t read1() = 0; virtual uint8_t read2() = 0; diff --git a/src/core/mdec.cc b/src/core/mdec.cc index 44577594d..88027db84 100644 --- a/src/core/mdec.cc +++ b/src/core/mdec.cc @@ -459,7 +459,7 @@ void PCSX::MDEC::dma0(uint32_t adr, uint32_t bcr, uint32_t chcr) { DMA_INTERRUPT<0>(); } -void PCSX::MDEC::mdec0Interrupt() { +void PCSX::MDEC::scheduledCallback0() { HW_DMA0_CHCR &= SWAP_LE32(~0x01000000); DMA_INTERRUPT<0>(); } @@ -557,7 +557,7 @@ void PCSX::MDEC::dma1(uint32_t adr, uint32_t bcr, uint32_t chcr) { } } -void PCSX::MDEC::mdec1Interrupt() { +void PCSX::MDEC::scheduledCallback1() { /* Author : gschwind * * in that case we have done all decoding stuff diff --git a/src/core/mdec.h b/src/core/mdec.h index 551244c22..cc79ffb76 100644 --- a/src/core/mdec.h +++ b/src/core/mdec.h @@ -37,8 +37,8 @@ class MDEC { uint32_t read1(); void dma0(uint32_t madr, uint32_t bcr, uint32_t chcr); void dma1(uint32_t madr, uint32_t bcr, uint32_t chcr); - void mdec0Interrupt(); - void mdec1Interrupt(); + void scheduledCallback0(); + void scheduledCallback1(); static const unsigned DSIZE = 8; static const unsigned DSIZE2 = DSIZE * DSIZE; diff --git a/src/core/psxdma.h b/src/core/psxdma.h index bb1247637..47c719e66 100644 --- a/src/core/psxdma.h +++ b/src/core/psxdma.h @@ -26,23 +26,23 @@ #include "core/r3000a.h" static inline void scheduleGPUDMAIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_GPUDMA, eCycle); + PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::GPUDMA, eCycle); } static inline void scheduleSPUDMAIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_SPUDMA, eCycle); + PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::SPUDMA, eCycle); } static inline void scheduleMDECOUTDMAIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_MDECOUTDMA, eCycle); + PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::MDECOUTDMA, eCycle); } static inline void scheduleMDECINDMAIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_MDECINDMA, eCycle); + PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::MDECINDMA, eCycle); } static inline void scheduleGPUOTCDMAIRQ(uint32_t eCycle) { - PCSX::g_emulator->m_cpu->scheduleInterrupt(PCSX::PSXINT_GPUOTCDMA, eCycle); + PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::GPUOTCDMA, eCycle); } /* diff --git a/src/core/r3000a.cc b/src/core/r3000a.cc index d2eef93a7..85958a213 100644 --- a/src/core/r3000a.cc +++ b/src/core/r3000a.cc @@ -284,41 +284,43 @@ void PCSX::R3000Acpu::branchTest() { if (m_regs.spuInterrupt.exchange(false)) PCSX::g_emulator->m_spu->interrupt(); - const uint32_t interrupts = m_regs.interrupt; + const uint32_t interrupts = m_regs.scheduleMask; int32_t lowestDistance = std::numeric_limits::max(); uint32_t lowestTarget = cycle; - uint32_t* targets = m_regs.intTargets; + uint32_t* targets = m_regs.scheduleTargets; if ((interrupts != 0) && (((int32_t)(m_regs.lowestTarget - cycle)) <= 0)) { -#define checkAndUpdate(irq, act) \ - { \ - constexpr uint32_t mask = 1 << irq; \ - if ((interrupts & mask) != 0) { \ - uint32_t target = targets[irq]; \ - int32_t dist = target - cycle; \ - if (dist > 0) { \ - if (lowestDistance > dist) { \ - lowestDistance = dist; \ - lowestTarget = target; \ - } \ - } else { \ - m_regs.interrupt &= ~mask; \ - PSXIRQ_LOG("Triggering interrupt %08x\n", irq); \ - act(); \ - } \ - } \ +#define checkAndUpdate(irq_, act) \ + { \ + constexpr unsigned irq = static_cast(irq_); \ + constexpr uint32_t mask = 1 << irq; \ + if ((interrupts & mask) != 0) { \ + uint32_t target = targets[irq]; \ + int32_t dist = target - cycle; \ + if (dist > 0) { \ + if (lowestDistance > dist) { \ + lowestDistance = dist; \ + lowestTarget = target; \ + } \ + } else { \ + m_regs.scheduleMask &= ~mask; \ + PSXIRQ_LOG("Calling scheduled callback %08x\n", irq); \ + act(); \ + } \ + } \ } - checkAndUpdate(PSXINT_SIO, g_emulator->m_sio->interrupt); - checkAndUpdate(PSXINT_SIO1, g_emulator->m_sio1->interrupt); - checkAndUpdate(PSXINT_CDR, g_emulator->m_cdrom->interrupt); - checkAndUpdate(PSXINT_CDREAD, g_emulator->m_cdrom->readInterrupt); - checkAndUpdate(PSXINT_GPUDMA, GPU::gpuInterrupt); - checkAndUpdate(PSXINT_MDECOUTDMA, g_emulator->m_mdec->mdec1Interrupt); - checkAndUpdate(PSXINT_SPUDMA, spuInterrupt); - checkAndUpdate(PSXINT_MDECINDMA, g_emulator->m_mdec->mdec0Interrupt); - checkAndUpdate(PSXINT_GPUOTCDMA, gpuotcInterrupt); - checkAndUpdate(PSXINT_CDRDMA, g_emulator->m_cdrom->dmaInterrupt); + checkAndUpdate(Schedule::SIO, g_emulator->m_sio->scheduledCallback); + checkAndUpdate(Schedule::SIO1, g_emulator->m_sio1->scheduledCallback); + checkAndUpdate(Schedule::CDRFIFO, g_emulator->m_cdrom->fifoScheduledCallback); + checkAndUpdate(Schedule::CDRCOMMANDS, g_emulator->m_cdrom->commandsScheduledCallback); + checkAndUpdate(Schedule::CDREAD, g_emulator->m_cdrom->readScheduledCallback); + checkAndUpdate(Schedule::GPUDMA, GPU::gpuInterrupt); + checkAndUpdate(Schedule::MDECOUTDMA, g_emulator->m_mdec->scheduledCallback1); + checkAndUpdate(Schedule::SPUDMA, spuInterrupt); + checkAndUpdate(Schedule::MDECINDMA, g_emulator->m_mdec->scheduledCallback0); + checkAndUpdate(Schedule::GPUOTCDMA, gpuotcInterrupt); + checkAndUpdate(Schedule::CDRDMA, g_emulator->m_cdrom->scheduleDmaCallback); m_regs.lowestTarget = lowestTarget; } if ((psxHu32(0x1070) & psxHu32(0x1074)) && ((m_regs.CP0.n.Status & 0x401) == 0x401)) { diff --git a/src/core/r3000a.h b/src/core/r3000a.h index bb315ea9e..af4917089 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -174,17 +174,18 @@ typedef union { PAIR p[32]; } psxCP2Ctrl; -enum { - PSXINT_SIO = 0, - PSXINT_SIO1, - PSXINT_CDR, - PSXINT_CDREAD, - PSXINT_GPUDMA, - PSXINT_MDECOUTDMA, - PSXINT_SPUDMA, - PSXINT_MDECINDMA, - PSXINT_GPUOTCDMA, - PSXINT_CDRDMA, +enum class Schedule : unsigned { + SIO = 0, + SIO1, + CDRFIFO, + CDRCOMMANDS, + CDREAD, + GPUDMA, + MDECOUTDMA, + SPUDMA, + MDECINDMA, + GPUOTCDMA, + CDRDMA, }; struct psxRegisters { @@ -196,9 +197,9 @@ struct psxRegisters { uint32_t code; // The current instruction uint32_t cycle; uint32_t previousCycles; - uint32_t interrupt; + uint32_t scheduleMask; std::atomic spuInterrupt; - uint32_t intTargets[32]; + uint32_t scheduleTargets[32]; uint32_t lowestTarget; uint8_t ICache_Addr[0x1000]; uint8_t ICache_Code[0x1000]; @@ -297,25 +298,32 @@ class R3000Acpu { void psxSetPGXPMode(uint32_t pgxpMode); - void scheduleInterrupt(unsigned interrupt, uint32_t eCycle) { - PSXIRQ_LOG("Scheduling interrupt %08x at %08x\n", interrupt, eCycle); + void schedule(Schedule s_, uint32_t eCycle) { + unsigned s = static_cast(s_); + PSXIRQ_LOG("Scheduling callback %08x at %08x\n", s, eCycle); const uint32_t cycle = m_regs.cycle; - uint32_t target = uint32_t(cycle + eCycle * m_interruptScales[interrupt]); - m_regs.interrupt |= (1 << interrupt); - m_regs.intTargets[interrupt] = target; + uint32_t target = uint32_t(cycle + eCycle * m_scheduleScales[s]); + m_regs.scheduleMask |= (1 << s); + m_regs.scheduleTargets[s] = target; int32_t lowest = m_regs.lowestTarget - cycle; int32_t maybeNewLowest = target - cycle; if (maybeNewLowest < lowest) m_regs.lowestTarget = target; } + void unschedule(Schedule s_) { + unsigned s = static_cast(s_); + PSXIRQ_LOG("Unscheduling callback %08x\n", s); + m_regs.scheduleMask &= ~(1 << s); + } + psxRegisters m_regs; - float m_interruptScales[15] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, - 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; + float m_scheduleScales[15] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; bool m_shellStarted = false; virtual void Reset() { invalidateCache(); - m_regs.interrupt = 0; + m_regs.scheduleMask = 0; } bool m_inISR = false; bool m_nextIsDelaySlot = false; diff --git a/src/core/sio.cc b/src/core/sio.cc index e22bf999f..0ecb47ac1 100644 --- a/src/core/sio.cc +++ b/src/core/sio.cc @@ -307,7 +307,7 @@ void PCSX::SIO::writeCtrl16(uint16_t value) { m_bufferIndex = 0; m_regs.status = StatusFlags::TX_DATACLEAR | StatusFlags::TX_FINISHED; psxHu32ref(0x1044) = SWAP_LEu32(m_regs.status); - PCSX::g_emulator->m_cpu->m_regs.interrupt &= ~(1 << PCSX::PSXINT_SIO); + g_emulator->m_cpu->unschedule(Schedule::SIO); m_currentDevice = DeviceType::None; } @@ -348,7 +348,7 @@ uint16_t PCSX::SIO::readStatus16() { return hard; } -void PCSX::SIO::interrupt() { +void PCSX::SIO::scheduledCallback() { SIO0_LOG("Sio Interrupt (CP0.Status = %x)\n", PCSX::g_emulator->m_cpu->m_regs.CP0.n.Status); m_regs.status |= StatusFlags::IRQ; psxHu32ref(0x1044) = SWAP_LEu32(m_regs.status); diff --git a/src/core/sio.h b/src/core/sio.h index 23c7c1cc5..ca0f7bd1e 100644 --- a/src/core/sio.h +++ b/src/core/sio.h @@ -93,7 +93,7 @@ class SIO { void acknowledge(); void init(); - void interrupt(); + void scheduledCallback(); void reset(); bool copyMcdFile(McdBlock block); @@ -230,7 +230,7 @@ class SIO { bool isReceiveIRQReady(); bool isTransmitReady(); static inline void scheduleInterrupt(uint32_t eCycle) { - g_emulator->m_cpu->scheduleInterrupt(PSXINT_SIO, eCycle); + g_emulator->m_cpu->schedule(Schedule::SIO, eCycle); #if 0 // Breaks Twisted Metal 2 intro m_statusReg &= ~RX_FIFONOTEMPTY; diff --git a/src/core/sio1.cc b/src/core/sio1.cc index fed4d76e1..735faeef6 100644 --- a/src/core/sio1.cc +++ b/src/core/sio1.cc @@ -126,7 +126,7 @@ void PCSX::SIO1::sio1StateMachine() { } } -void PCSX::SIO1::interrupt() { +void PCSX::SIO1::scheduledCallback() { SIO1_LOG("SIO1 Interrupt (CP0.Status = %x)\n", PCSX::g_emulator->m_cpu->m_regs.CP0.n.Status); psxHu32ref(0x1070) |= SWAP_LEu32(IRQ8_SIO); m_regs.status |= SR_IRQ; @@ -281,7 +281,7 @@ void PCSX::SIO1::writeCtrl16(uint16_t v) { m_sio1fifo.asA()->reset(); } - PCSX::g_emulator->m_cpu->m_regs.interrupt &= ~(1 << PCSX::PSXINT_SIO1); + g_emulator->m_cpu->unschedule(Schedule::SIO1); } if (!(m_regs.control & CR_RXEN)) { diff --git a/src/core/sio1.h b/src/core/sio1.h index 57eee50e9..6aa1cd432 100644 --- a/src/core/sio1.h +++ b/src/core/sio1.h @@ -70,7 +70,7 @@ class SIO1 { enum class SIO1Mode { Raw, Protobuf }; SIO1Mode m_sio1Mode = SIO1Mode::Protobuf; SIO1Mode getSIO1Mode() { return m_sio1Mode; } - void interrupt(); + void scheduledCallback(); void poll() { if (fifoError()) return; @@ -93,7 +93,7 @@ class SIO1 { m_decodeState = READ_SIZE; messageSize = 0; initialMessage = true; - g_emulator->m_cpu->m_regs.interrupt &= ~(1 << PCSX::PSXINT_SIO1); + g_emulator->m_cpu->unschedule(Schedule::SIO1); } void stopSIO1Connection() { @@ -257,7 +257,7 @@ class SIO1 { enum { READ_SIZE, READ_MESSAGE } m_decodeState = READ_SIZE; - inline void scheduleInterrupt(uint32_t eCycle) { g_emulator->m_cpu->scheduleInterrupt(PSXINT_SIO1, eCycle); } + inline void scheduleInterrupt(uint32_t eCycle) { g_emulator->m_cpu->schedule(Schedule::SIO1, eCycle); } void updateStat(); void transmitData(); diff --git a/src/core/sstate.cc b/src/core/sstate.cc index b6b794079..1b0b5d505 100644 --- a/src/core/sstate.cc +++ b/src/core/sstate.cc @@ -51,7 +51,7 @@ PCSX::SaveStates::SaveState PCSX::SaveStates::constructSaveState() { PC{g_emulator->m_cpu->m_regs.pc}, Code{g_emulator->m_cpu->m_regs.code}, Cycle{g_emulator->m_cpu->m_regs.cycle}, - Interrupt{g_emulator->m_cpu->m_regs.interrupt}, + ScheduleMask{g_emulator->m_cpu->m_regs.scheduleMask}, ICacheAddr{g_emulator->m_cpu->m_regs.ICache_Addr}, ICacheCode{g_emulator->m_cpu->m_regs.ICache_Code}, NextIsDelaySlot{g_emulator->m_cpu->m_nextIsDelaySlot}, @@ -74,7 +74,7 @@ PCSX::SaveStates::SaveState PCSX::SaveStates::constructSaveState() { DelaySlotFromLink{g_emulator->m_cpu->m_delayedLoadInfo[1].fromLink}, }, CurrentDelayedLoad{g_emulator->m_cpu->m_currentDelayedLoad}, - IntTargetsField{g_emulator->m_cpu->m_regs.intTargets}, + ScheduleTargetsField{g_emulator->m_cpu->m_regs.scheduleTargets}, InISR{g_emulator->m_cpu->m_inISR}, }, GPU{}, diff --git a/src/core/sstate.h b/src/core/sstate.h index 808dd063c..8500a1d48 100644 --- a/src/core/sstate.h +++ b/src/core/sstate.h @@ -56,7 +56,7 @@ typedef Protobuf::RepeatedFieldRef typedef Protobuf::FieldRef PC; typedef Protobuf::FieldRef Code; typedef Protobuf::FieldRef Cycle; -typedef Protobuf::FieldRef Interrupt; +typedef Protobuf::FieldRef ScheduleMask; // skip id 9 typedef Protobuf::FieldPtr, TYPESTRING("icache_addr"), 10> ICacheAddr; typedef Protobuf::FieldPtr, TYPESTRING("icache_code"), 11> ICacheCode; @@ -75,11 +75,11 @@ typedef Protobuf::Message DelaySlotInfo1; typedef Protobuf::MessageField DelaySlotInfo2; typedef Protobuf::FieldRef CurrentDelayedLoad; -typedef Protobuf::RepeatedFieldRef IntTargetsField; +typedef Protobuf::RepeatedFieldRef ScheduleTargetsField; typedef Protobuf::FieldRef InISR; -typedef Protobuf::Message + ScheduleTargetsField, InISR> Registers; typedef Protobuf::MessageField RegistersField; diff --git a/src/gui/gui.cc b/src/gui/gui.cc index b7e640723..1ac260cd3 100644 --- a/src/gui/gui.cc +++ b/src/gui/gui.cc @@ -1881,18 +1881,17 @@ of the emulator to take effect.)"); void PCSX::GUI::interruptsScaler() { static const char* names[] = { - "SIO", "SIO1", "CDR", "CDR Read", "GPU DMA", "MDEC Out DMA", "SPU DMA", - "GPU Busy", "MDEC In DMA", "GPU OTC DMA", "CDR DMA", "SPU", "CDR Decoded Buffer", "CDR Lid Seek", - "CDR Play", + "SIO", "SIO1", "CDR FIFO", "CDR Command", "CDR Reads", "GPU DMA", + "MDEC Out DMA", "SPU DMA", "MDEC In DMA", "GPU OTC DMA", "CDR DMA", }; - if (ImGui::Begin(_("Interrupt Scaler"), &m_showInterruptsScaler)) { + if (ImGui::Begin(_("Scheduler Scaler"), &m_showInterruptsScaler)) { if (ImGui::Button(_("Reset all"))) { - for (auto& scale : g_emulator->m_cpu->m_interruptScales) { + for (auto& scale : g_emulator->m_cpu->m_scheduleScales) { scale = 1.0f; } } unsigned counter = 0; - for (auto& scale : g_emulator->m_cpu->m_interruptScales) { + for (auto& scale : g_emulator->m_cpu->m_scheduleScales) { ImGui::SliderFloat(names[counter], &scale, 0.0f, 100.0f, "%.3f", ImGuiSliderFlags_AlwaysClamp); counter++; } diff --git a/src/gui/widgets/registers.cc b/src/gui/widgets/registers.cc index 45aa3123f..214989684 100644 --- a/src/gui/widgets/registers.cc +++ b/src/gui/widgets/registers.cc @@ -175,7 +175,7 @@ void PCSX::Widgets::Registers::draw(PCSX::GUI* gui, PCSX::psxRegisters* register ImGui::Text("pc : %08x", registers->pc); makeEditableRegister("pc", registers->pc); ImGui::Text("cycle: %08x", registers->cycle); - ImGui::Text("int : %08x", registers->interrupt); + ImGui::Text("sched: %08x", registers->scheduleMask); ImGui::EndTabItem(); } ImGui::PopFont(); From a9523e4f194ef647960aa1d00dc7bf5c37b62f0c Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 7 Jan 2023 16:05:05 -0800 Subject: [PATCH 133/185] Derp. --- src/mips/tests/cdrom/cdrom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index e39c2b85d..0cbd95bd7 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -39,7 +39,7 @@ SOFTWARE. #include "cester-hw.c" -#if 0 +#if 1 #include "cdlgetlocl.c" #include "cdlgetlocp.c" #include "cdlgettd.c" From 1a3148c166a5823a54ef49c08466aff6248023e6 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 9 Jan 2023 18:07:48 -0800 Subject: [PATCH 134/185] One more racy test to really close the loop. --- src/mips/tests/cdrom/race.c | 90 +++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 3 deletions(-) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 91f8f52ae..dec6f1f57 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -202,7 +202,7 @@ CESTER_TEST(raceGetTD1AndNop, test_instance, ramsyscall_printf("GetTD1 followed by Nop: ack in %ius\n", ackTime); ) -CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, +CESTER_TEST(raceSeekP2to85AckWaitAndNop, test_instance, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -215,7 +215,7 @@ CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, return; } - int setLocDone = setLoc(0x80, 0, 0); + int setLocDone = setLoc(0x85, 0, 0); if (!setLocDone) { cester_assert_true(setLocDone); return; @@ -286,7 +286,91 @@ CESTER_TEST(raceSeekP2to80WaitAckAndNop, test_instance, cester_assert_uint_lt(ackTime, 7000); cester_assert_uint_ge(ackTime2, 500); cester_assert_uint_lt(ackTime2, 7000); - ramsyscall_printf("SeekP from 00:02:00 to 80:00:00 with Nop in between: ack in %ius, ack2 in %ius, errored in %ius\n", ackTime, ackTime2, errorTime); + ramsyscall_printf("SeekP from 00:02:00 to 85:00:00 with Nop in between: ack in %ius, ack2 in %ius, errored in %ius\n", ackTime, ackTime2, errorTime); +) + +CESTER_TEST(raceSeekP2to85WaitAckAndNop, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int seekDone = seekPTo(0, 2, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + int setLocDone = setLoc(0x85, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + // wait 50ms for things to settle + while (updateTime() < 50000); + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_SEEKP; + uint8_t ctrl0 = CDROM_REG0 & ~3; + + while (CDROM_REG0 & 0x80); + + CDROM_REG1 = CDL_NOP; + uint8_t ctrl0b = CDROM_REG0 & ~3; + + initializeTime(); + // Wait 10s... + ramsyscall_printf("Waiting 6s...\n"); + while (updateTime() < 6000000); + ramsyscall_printf("Done...\n"); + + initializeTime(); + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + uint32_t timeout = 150000; + int gotIRQ = waitCDRomIRQWithTimeout(&timeout); + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x98, ctrl0); + cester_assert_uint_eq(0xb8, ctrl0b); + cester_assert_uint_eq(0xb8, ctrl1); + cester_assert_uint_eq(0x98, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_false(gotIRQ); + // This one really should be 0, but just in case. + cester_assert_uint_lt(ackTime, 150); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + ramsyscall_printf("SeekP from 00:02:00 to 85:00:00 then stall with Nop: ack in %ius, ack2 in %ius\n", ackTime, ackTime2); ) CESTER_TEST(raceNopWaitAndNop, test_instances, From 1e372ddf3c1799da24d9d364a6e076753e359833 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 9 Jan 2023 21:32:35 -0800 Subject: [PATCH 135/185] New state machine. Again. --- src/core/cdrom.cc | 726 ++++++++++++++++++--------------------------- src/core/cdrom.h | 75 +++-- src/core/r3000a.h | 5 + src/core/sstate.cc | 11 - src/core/sstate.h | 5 +- 5 files changed, 355 insertions(+), 467 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 60d163df1..6cd481947 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -75,7 +75,7 @@ class CDRomImpl final : public PCSX::CDRom { static constexpr size_t c_cdCmdEnumCount = magic_enum::enum_count(); static constexpr bool isValidBCD(uint8_t value) { return (value & 0x0f) <= 9 && (value & 0xf0) <= 0x90; } - static std::optional getMSF(uint8_t *msf) { + static std::optional getMSF(const uint8_t *msf) { bool validBCD = isValidBCD(msf[0]) && isValidBCD(msf[1]) && isValidBCD(msf[2]); if (!validBCD) return {}; uint8_t m = PCSX::IEC60908b::btoi(msf[0]); @@ -90,54 +90,29 @@ class CDRomImpl final : public PCSX::CDRom { void reset() override { m_dataFIFOIndex = 0; m_dataFIFOSize = 0; - m_paramFIFOSize = 0; - m_responseFIFOIndex = 0; - m_responseFIFOSize = 0; m_registerIndex = 0; - m_busy = false; - m_state = 0; - m_command = 0; - m_cause = Cause::None; m_currentPosition.reset(); m_seekPosition.reset(); - m_gotAck = false; - m_waitingAck = false; m_speed = Speed::Simple; m_speedChanged = false; m_status = Status::Idle; - m_readDelayed = 0; m_dataRequested = false; m_causeMask = 0x1f; m_subheaderFilter = false; m_realtime = false; + m_commandFifo.clear(); + m_commandExecuting.clear(); + m_responseFifo[0].clear(); + m_responseFifo[1].clear(); } - void fifoScheduledCallback() override { - if (m_errorArgumentsCount) { - m_errorArgumentsCount = false; - m_cause = Cause::Error; - m_paramFIFOSize = 0; - m_command = 0; - setResponse(getStatus() | 1); - appendResponse(0x20); - triggerIRQ(); - return; - } - auto handler = c_commandsHandlers[m_command]; - if (handler) { - (this->*handler)(); - } else { - setResponse(getStatus() | 1); - appendResponse(0x40); - m_cause = Cause::Error; - m_paramFIFOSize = 0; - m_state = 0; - m_command = 0; - triggerIRQ(); - } - } + void fifoScheduledCallback() override { maybeStartCommand(); } - void commandsScheduledCallback() override {} + void commandsScheduledCallback() override { + auto command = m_commandExecuting.value; + auto handler = c_commandsHandlers[command]; + (this->*handler)(m_commandExecuting, false); + } void readScheduledCallback() override { static const std::chrono::nanoseconds c_retryDelay = 50us; @@ -148,7 +123,6 @@ class CDRomImpl final : public PCSX::CDRom { m_status = Status::ReadingData; } if ((m_status == Status::Idle) || (m_status == Status::Seeking)) { - m_readDelayed = 0; m_readingType = ReadingType::None; if (debug) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: cancelling read.\n"); @@ -156,26 +130,15 @@ class CDRomImpl final : public PCSX::CDRom { return; } - if (m_command != 0) { - m_readDelayed++; - scheduleRead(c_retryDelay); - return; - } switch (m_status) { case Status::ReadingData: { unsigned track = m_iso->getTrack(m_currentPosition); if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { m_status = Status::Idle; - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(4); - triggerIRQ(); + maybeEnqueueError(4, 4); } else if (track == 0) { m_status = Status::Idle; - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(0x10); - triggerIRQ(); + maybeEnqueueError(4, 0x10); } else { m_invalidLocL = false; m_iso->readTrack(m_currentPosition); @@ -201,9 +164,6 @@ class CDRomImpl final : public PCSX::CDRom { break; } auto readDelay = computeReadDelay(); - readDelay -= m_readDelayed * c_retryDelay; - m_readDelayed = 0; - m_cause = Cause::DataReady; m_dataFIFOIndex = 0; m_dataFIFOPending = size; if (m_dataRequested) m_dataFIFOSize = size; @@ -213,8 +173,9 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: advancing to %s.\n", msfFormat); } - setResponse(getStatus()); - triggerIRQ(); + QueueElement ready; + ready.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::DataReady, ready); scheduleRead(readDelay); } } break; @@ -233,7 +194,7 @@ class CDRomImpl final : public PCSX::CDRom { } void scheduleFifo(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDRFIFO, cycles); } - void scheduleFifo(std::chrono::nanoseconds delay) { schedule(PCSX::psxRegisters::durationToCycles(delay)); } + void scheduleFifo(std::chrono::nanoseconds delay) { scheduleFifo(PCSX::psxRegisters::durationToCycles(delay)); } void schedule(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDRCOMMANDS, cycles); } void schedule(std::chrono::nanoseconds delay) { schedule(PCSX::psxRegisters::durationToCycles(delay)); } @@ -244,48 +205,29 @@ class CDRomImpl final : public PCSX::CDRom { void scheduleDMA(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDRDMA, cycles); } void scheduleDMA(std::chrono::nanoseconds delay) { scheduleDMA(PCSX::psxRegisters::durationToCycles(delay)); } - void triggerIRQ() { - assert(m_cause != Cause::None); - assert(!m_waitingAck); - uint8_t bit = 1 << (static_cast(m_cause) - 1); + void maybeTriggerIRQ(Cause cause, QueueElement &element) { + uint8_t causeValue = static_cast(cause); + uint8_t bit = 1 << (causeValue - 1); if (m_causeMask & bit) { - m_gotAck = false; + element.setValue(cause); + maybeEnqueueResponse(element); psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); const bool debug = PCSX::g_emulator->settings.get() .get(); if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] triggering IRQ with cause %d\n", regs.pc, - regs.cycle, static_cast(m_cause)); + regs.cycle, causeValue); } } else { if (PCSX::g_emulator->settings.get() .get()) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: wanted to trigger IRQ but cause %d is masked...\n", - static_cast(m_cause)); + causeValue); } } } - void setResponse(std::string_view response) { - std::copy(response.begin(), response.end(), m_responseFIFO); - m_responseFIFOSize = response.size(); - m_responseFIFOIndex = 0; - } - - void setResponse(uint8_t response) { - m_responseFIFO[0] = response; - m_responseFIFOSize = 1; - m_responseFIFOIndex = 0; - } - - void appendResponse(std::string_view response) { - std::copy(response.begin(), response.end(), m_responseFIFO + m_responseFIFOSize); - m_responseFIFOSize += response.size(); - } - - void appendResponse(uint8_t response) { m_responseFIFO[m_responseFIFOSize++] = response; } - uint8_t getStatus(bool resetLid = false) { bool lidOpen = isLidOpen(); if (resetLid && !lidOpen) m_wasLidOpened = false; @@ -309,11 +251,11 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t read0() override { uint8_t v01 = m_registerIndex & 3; uint8_t adpcmPlaying = 0; - uint8_t v3 = m_paramFIFOSize == 0 ? 0x08 : 0; - uint8_t v4 = paramFIFOAvailable() ? 0x10 : 0; - uint8_t v5 = responseFIFOHasData() ? 0x20 : 0; + uint8_t v3 = m_commandFifo.isPayloadEmpty() ? 0x08 : 0; + uint8_t v4 = !m_commandFifo.isPayloadFull() ? 0x10 : 0; + uint8_t v5 = !m_responseFifo[0].empty() ? 0x20 : 0; uint8_t v6 = m_dataFIFOSize != m_dataFIFOIndex ? 0x40 : 0; - uint8_t v7 = m_busy ? 0x80 : 0; + uint8_t v7 = m_commandFifo.hasValue ? 0x80 : 0; uint8_t ret = v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7; const bool debug = PCSX::g_emulator->settings.get() @@ -327,12 +269,8 @@ class CDRomImpl final : public PCSX::CDRom { } uint8_t read1() override { - uint8_t ret = 0; - if (!responseFIFOHasData()) { - ret = 0; - } else { - ret = m_responseFIFO[m_responseFIFOIndex++]; - } + uint8_t ret = m_responseFifo[0].readPayloadByte(); + // TODO: if empty, move response FIFO and maybe trigger IRQ. const bool debug = PCSX::g_emulator->settings.get() .get(); @@ -369,7 +307,7 @@ class CDRomImpl final : public PCSX::CDRom { case 1: { // cause // TODO: add bit 4 - ret = magic_enum::enum_integer(m_cause) | 0xe0; + ret = m_responseFifo[0].getValue() | 0xe0; } break; } const bool debug = PCSX::g_emulator->settings.get() @@ -401,17 +339,17 @@ class CDRomImpl final : public PCSX::CDRom { m_registerIndex, value); } switch (m_registerIndex) { - case 0: { - if (m_command != 0) { - // The CD-Rom controller is already executing a command. - // This basically results in undefined behavior. We'll still - // have to address this, as some games will do it anyway. - PCSX::g_system->log(PCSX::LogClass::CDROM, - "CD-Rom: command while controller is already executing one!\n"); - PCSX::g_system->pause(); + case 0: + m_commandFifo.value = value; + if (!m_commandFifo.hasValue) { + if (PCSX::g_emulator->settings.get() + .get()) { + logCDROM(m_commandFifo); + } + scheduleFifo(1ms); } - startCommand(value); - } break; + m_commandFifo.hasValue = true; + break; case 1: { // ?? PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:1 not available yet\n"); @@ -439,7 +377,7 @@ class CDRomImpl final : public PCSX::CDRom { } switch (m_registerIndex) { case 0: { - if (paramFIFOAvailable()) m_paramFIFO[m_paramFIFOSize++] = value; + m_commandFifo.pushPayloadData(value); } break; case 1: { m_causeMask = value; @@ -492,12 +430,8 @@ class CDRomImpl final : public PCSX::CDRom { ack = true; } if (ack) { - m_cause = Cause::None; - if (m_waitingAck) { - m_waitingAck = false; - schedule(350us); - } - m_gotAck = true; + m_responseFifo[0].valueRead = true; + // TODO: if empty, move response FIFO and maybe trigger IRQ. return; } if (value & 0x10) { @@ -509,7 +443,7 @@ class CDRomImpl final : public PCSX::CDRom { // TODO: act on this? } if (value & 0x40) { - m_paramFIFOSize = 0; + m_commandFifo.payloadSize = 0; return; } PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:1(%02x) not available yet\n", value); @@ -548,44 +482,42 @@ class CDRomImpl final : public PCSX::CDRom { } } - void startCommand(uint8_t command) { - m_state = 0; - m_command = command; - if (PCSX::g_emulator->settings.get() - .get()) { - logCDROM(command); - } + void maybeEnqueueError(uint8_t mask1, uint8_t mask2) { + QueueElement error; + error.pushPayloadData(getStatus() | mask1); + error.pushPayloadData(mask2); + maybeTriggerIRQ(Cause::Error, error); + } - if (command > 30) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command\n"); - PCSX::g_system->pause(); + void maybeStartCommand() { + auto command = m_commandFifo.value; + static constexpr unsigned c_commandMax = sizeof(c_commandsArgumentsCount) / sizeof(c_commandsArgumentsCount[0]); + if (command >= c_commandMax) { + maybeEnqueueError(1, 0x40); + endCommand(); return; } - - auto count = c_commandsArgumentsCount[command]; - if (count >= 0) { - if (m_paramFIFOSize != count) { - m_errorArgumentsCount = true; - schedule(750us); - return; - } + auto expectedCount = c_commandsArgumentsCount[command]; + if ((expectedCount >= 0) && (expectedCount != m_commandFifo.payloadSize)) { + maybeEnqueueError(1, 0x20); + endCommand(); + return; } - auto handler = c_commandsHandlers[command]; - - std::chrono::nanoseconds initialDelay = c_commandsInitialDelay[command]; - - if (handler == nullptr) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unknown CD-Rom command %i\n", m_command); - if (PCSX::g_emulator->settings.get() - .get()) { - PCSX::g_system->pause(); + if (handler) { + if ((this->*handler)(m_commandFifo, true)) { + m_commandExecuting = m_commandFifo; } - initialDelay = 750us; + m_commandFifo.clear(); + } else { + maybeEnqueueError(1, 0x40); + endCommand(); + return; } + } - m_state = 1; - schedule(initialDelay); + void endCommand() { + if (!responseFifoFull() && !m_commandFifo.empty()) scheduleFifo(1ms); } enum class SeekType { DATA, CDDA }; @@ -610,146 +542,132 @@ class CDRomImpl final : public PCSX::CDRom { std::chrono::nanoseconds computeReadDelay() { return m_speed == Speed::Simple ? 13333us : 6666us; } // Command 1. - void cdlNop() { - setResponse(getStatus(true)); - m_cause = Cause::Acknowledge; - m_command = 0; - triggerIRQ(); + bool cdlNop(const QueueElement &command, bool start) { + QueueElement response; + response.pushPayloadData(getStatus(true)); + maybeTriggerIRQ(Cause::Acknowledge, response); + endCommand(); + return false; } // Command 2. - void cdlSetLoc() { + bool cdlSetLoc(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? // What happens when issued during Read / Play? - auto maybeMSF = getMSF(m_paramFIFO); + auto maybeMSF = getMSF(command.payload); + QueueElement response; + Cause cause; if (maybeMSF.has_value()) { - setResponse(getStatus()); - m_cause = Cause::Acknowledge; + response.pushPayloadData(getStatus()); + cause = Cause::Acknowledge; + maybeTriggerIRQ(cause, response); m_seekPosition = maybeMSF.value(); } else { - setResponse(getStatus() | 1); - appendResponse(0x10); - m_cause = Cause::Error; + maybeEnqueueError(1, 0x10); } - m_paramFIFOSize = 0; - m_command = 0; - triggerIRQ(); + endCommand(); + return false; } // Command 6. - void cdlReadN() { + bool cdlReadN(const QueueElement &command, bool start) { auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); if (m_speedChanged) { m_speedChanged = false; seekDelay += 650ms; } scheduleRead(seekDelay + computeReadDelay()); - m_cause = Cause::Acknowledge; - setResponse(getStatus()); + QueueElement response; + response.pushPayloadData(getStatus()); m_currentPosition = m_seekPosition; - m_command = 0; m_startReading = true; m_readingType = ReadingType::Normal; - triggerIRQ(); + maybeTriggerIRQ(Cause::Acknowledge, response); + endCommand(); + return false; } // Command 9. - void cdlPause() { - switch (m_state) { - case 1: { - if (m_status == Status::Idle) { - schedule(200us); - } else { - schedule(m_speed == Speed::Simple ? 70ms : 35ms); - } - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - triggerIRQ(); - } break; - case 2: - m_status = Status::Idle; - m_invalidLocL = true; - if (!m_gotAck) { - m_waitingAck = true; - m_state = 3; - break; - } - [[fallthrough]]; - case 3: - m_cause = Cause::Complete; - m_command = 0; - setResponse(getStatus()); - triggerIRQ(); - break; + bool cdlPause(const QueueElement &command, bool start) { + if (start) { + if (m_status == Status::Idle) { + schedule(200us); + } else { + schedule(m_speed == Speed::Simple ? 70ms : 35ms); + } + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + return true; + } else { + m_status = Status::Idle; + m_invalidLocL = true; + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Complete, response); + endCommand(); + return false; } } // Command 10. - void cdlInit() { - switch (m_state) { - case 1: - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - triggerIRQ(); - schedule(120ms); - break; - case 2: - // TODO: figure out exactly the various states of the CD-Rom controller - // that are being reset, and their value. - m_motorOn = true; - m_speedChanged = false; - m_currentPosition.reset(); - m_currentPosition.s = 2; - m_seekPosition.reset(); - m_seekPosition.s = 2; - m_invalidLocL = false; - m_speed = Speed::Simple; - m_status = Status::Idle; - m_causeMask = 0x1f; - memset(m_lastLocP, 0, sizeof(m_lastLocP)); - if (!m_gotAck) { - m_waitingAck = true; - m_state = 3; - break; - } - [[fallthrough]]; - case 3: - m_cause = Cause::Complete; - m_command = 0; - setResponse(getStatus()); - triggerIRQ(); - break; + bool cdlInit(const QueueElement &command, bool start) { + if (start) { + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + schedule(120ms); + return true; + } else { + // TODO: figure out exactly the various states of the CD-Rom controller + // that are being reset, and their value. + m_motorOn = true; + m_speedChanged = false; + m_currentPosition.reset(); + m_currentPosition.s = 2; + m_seekPosition.reset(); + m_seekPosition.s = 2; + m_invalidLocL = false; + m_speed = Speed::Simple; + m_status = Status::Idle; + m_causeMask = 0x1f; + memset(m_lastLocP, 0, sizeof(m_lastLocP)); + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Complete, response); + endCommand(); + return false; } } // Command 11 - void cdlMute() { + bool cdlMute(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? - setResponse(getStatus()); - m_cause = Cause::Acknowledge; - m_command = 0; PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: Mute - not yet implemented.\n"); - triggerIRQ(); + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + endCommand(); + return false; } // Command 12 - void cdlDemute() { + bool cdlDemute(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? - setResponse(getStatus()); - m_cause = Cause::Acknowledge; - m_command = 0; PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: Demute - not yet implemented.\n"); - triggerIRQ(); + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + endCommand(); + return false; } // Command 14 - void cdlSetMode() { - uint8_t mode = m_paramFIFO[0]; + bool cdlSetMode(const QueueElement &command, bool start) { + uint8_t mode = command.payload[0]; // TODO: add the rest of the mode bits. if (mode & 0x80) { if (m_speed == Speed::Simple) { @@ -783,234 +701,193 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode:\n", mode); PCSX::g_system->pause(); } - setResponse(getStatus()); - m_cause = Cause::Acknowledge; - m_paramFIFOSize = 0; - m_command = 0; - triggerIRQ(); + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + endCommand(); + return false; } // Command 16. - void cdlGetLocL() { + bool cdlGetLocL(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? if (m_invalidLocL) { - setResponse(getStatus() | 1); - appendResponse(0x80); - m_cause = Cause::Error; + maybeEnqueueError(1, 0x80); } else { - setResponse(std::string_view((char *)m_lastLocL, sizeof(m_lastLocL))); - m_cause = Cause::Acknowledge; + QueueElement response; + response.pushPayloadData(std::string_view((char *)m_lastLocL, sizeof(m_lastLocL))); + maybeTriggerIRQ(Cause::Acknowledge, response); } - m_command = 0; - triggerIRQ(); + endCommand(); + return false; } // Command 17. - void cdlGetLocP() { + bool cdlGetLocP(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? m_iso->getLocP(m_currentPosition, m_lastLocP); - setResponse(std::string_view((char *)m_lastLocP, sizeof(m_lastLocP))); - m_cause = Cause::Acknowledge; - m_command = 0; - triggerIRQ(); + QueueElement response; + response.pushPayloadData(std::string_view((char *)m_lastLocP, sizeof(m_lastLocP))); + maybeTriggerIRQ(Cause::Acknowledge, response); + endCommand(); + return false; } // Command 19. - void cdlGetTN() { + bool cdlGetTN(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? - setResponse(getStatus()); - appendResponse(1); - appendResponse(PCSX::IEC60908b::itob(m_iso->getTN())); - m_cause = Cause::Acknowledge; - m_command = 0; - triggerIRQ(); + QueueElement response; + response.pushPayloadData(getStatus()); + response.pushPayloadData(1); + response.pushPayloadData(PCSX::IEC60908b::itob(m_iso->getTN())); + maybeTriggerIRQ(Cause::Acknowledge, response); + endCommand(); + return false; } // Command 20. - void cdlGetTD() { + bool cdlGetTD(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? - auto track = PCSX::IEC60908b::btoi(m_paramFIFO[0]); - if (!isValidBCD(m_paramFIFO[0]) || (track > m_iso->getTN())) { - setResponse(getStatus() | 1); - appendResponse(0x10); - m_cause = Cause::Error; + auto track = PCSX::IEC60908b::btoi(command.payload[0]); + if (!isValidBCD(command.payload[0]) || (track > m_iso->getTN())) { + maybeEnqueueError(1, 0x10); } else { - setResponse(getStatus()); auto td = m_iso->getTD(track); - appendResponse(PCSX::IEC60908b::itob(td.m)); - appendResponse(PCSX::IEC60908b::itob(td.s)); - m_cause = Cause::Acknowledge; + QueueElement response; + response.pushPayloadData(getStatus()); + response.pushPayloadData(PCSX::IEC60908b::itob(td.m)); + response.pushPayloadData(PCSX::IEC60908b::itob(td.s)); + maybeTriggerIRQ(Cause::Acknowledge, response); } - m_paramFIFOSize = 0; - m_command = 0; - triggerIRQ(); + endCommand(); + return false; } // Command 21. - void cdlSeekL() { - switch (m_state) { - case 1: { - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - triggerIRQ(); - auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); - if (m_speedChanged) { - m_speedChanged = false; - seekDelay += 650ms; - } - m_status = Status::Seeking; - schedule(seekDelay); - } break; - case 2: - m_status = Status::Idle; - if (!m_gotAck) { - m_waitingAck = true; - m_state = 3; - break; - } - [[fallthrough]]; - case 3: { - m_currentPosition = m_seekPosition; - unsigned track = m_iso->getTrack(m_seekPosition); - if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(4); - } else if (track == 0) { - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(0x10); - } else { - m_cause = Cause::Complete; - setResponse(getStatus()); - } - m_invalidLocL = true; - m_command = 0; - triggerIRQ(); - } break; + bool cdlSeekL(const QueueElement &command, bool start) { + if (start) { + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; + } + m_status = Status::Seeking; + schedule(seekDelay); + return true; + } else { + m_status = Status::Idle; + m_currentPosition = m_seekPosition; + unsigned track = m_iso->getTrack(m_seekPosition); + if (m_iso->getTrackType(track) == PCSX::CDRIso::TrackType::CDDA) { + maybeEnqueueError(4, 4); + } else if (track == 0) { + maybeEnqueueError(4, 0x10); + } else { + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Complete, response); + } + m_invalidLocL = true; + endCommand(); + return false; } } // Command 22. - void cdlSeekP() { - switch (m_state) { - case 1: { - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - triggerIRQ(); - auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::CDDA); - if (m_speedChanged) { - m_speedChanged = false; - seekDelay += 650ms; - } - m_status = Status::Seeking; - schedule(seekDelay); - } break; - case 2: - m_status = Status::Idle; - if (!m_gotAck) { - m_waitingAck = true; - m_state = 3; - break; - } - [[fallthrough]]; - case 3: { - MSF fudge = m_seekPosition - MSF{m_seekPosition.toLBA() / 32768}; - m_currentPosition = fudge; - if (m_iso->getTrack(m_seekPosition) == 0) { - m_cause = Cause::Error; - setResponse(getStatus() | 4); - appendResponse(0x10); - } else { - m_cause = Cause::Complete; - setResponse(getStatus()); - } - m_invalidLocL = true; - m_command = 0; - triggerIRQ(); - } break; + bool cdlSeekP(const QueueElement &command, bool start) { + if (start) { + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::CDDA); + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; + } + m_status = Status::Seeking; + schedule(seekDelay); + return true; + } else { + m_status = Status::Idle; + MSF fudge = m_seekPosition - MSF{m_seekPosition.toLBA() / 32768}; + m_currentPosition = fudge; + if (m_iso->getTrack(m_seekPosition) == 0) { + maybeEnqueueError(4, 0x10); + } else { + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Complete, response); + } + m_invalidLocL = true; + endCommand(); + return false; } } // Command 25. - void cdlTest() { + bool cdlTest(const QueueElement &command, bool start) { static constexpr uint8_t c_test20[] = {0x94, 0x09, 0x19, 0xc0}; - if (m_paramFIFOSize == 0) { - m_cause = Cause::Error; - m_paramFIFOSize = 0; - m_command = 0; - setResponse(getStatus() | 1); - appendResponse(0x20); - triggerIRQ(); - return; + if (command.isPayloadEmpty()) { + maybeEnqueueError(1, 0x20); + endCommand(); + return false; } - switch (m_paramFIFO[0]) { + switch (command.payload[0]) { case 0x20: - if (m_paramFIFOSize == 1) { - setResponse(std::string_view((const char *)c_test20, sizeof(c_test20))); - m_cause = Cause::Acknowledge; + if (command.payloadSize == 1) { + QueueElement response; + response.pushPayloadData(std::string_view((const char *)c_test20, sizeof(c_test20))); + maybeTriggerIRQ(Cause::Acknowledge, response); } else { - setResponse(getStatus() | 1); - appendResponse(0x20); - m_cause = Cause::Error; + maybeEnqueueError(1, 0x20); } break; default: - setResponse(getStatus() | 1); - appendResponse(0x10); - m_cause = Cause::Error; + maybeEnqueueError(1, 0x10); break; } - m_paramFIFOSize = 0; - m_command = 0; - triggerIRQ(); + endCommand(); + return false; } // Command 26. - void cdlID() { - switch (m_state) { - case 1: - m_cause = Cause::Acknowledge; - m_state = 2; - setResponse(getStatus()); - triggerIRQ(); - schedule(5ms); - break; - case 2: - if (!m_gotAck) { - m_waitingAck = true; - m_state = 3; - break; - } - [[fallthrough]]; - case 3: { - // Adjust this response for various types of discs and situations. - m_cause = Cause::Complete; - setResponse(getStatus()); - appendResponse(0x00); - appendResponse(0x20); - appendResponse(0x00); - appendResponse("PCSX"sv); - m_command = 0; - triggerIRQ(); - } break; + bool cdlID(const QueueElement &command, bool start) { + if (start) { + QueueElement response; + response.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::Acknowledge, response); + schedule(5ms); + return true; + } else { + // Adjust this response for various types of discs and situations. + QueueElement response; + response.pushPayloadData(getStatus()); + response.pushPayloadData(0x00); + response.pushPayloadData(0x20); + response.pushPayloadData(0x00); + response.pushPayloadData("PCSX"sv); + maybeTriggerIRQ(Cause::Complete, response); + endCommand(); + return false; } } // Command 27. - void cdlReadS() { - cdlReadN(); + bool cdlReadS(const QueueElement &command, bool start) { + bool ret = cdlReadN(command, start); m_readingType = ReadingType::Streaming; + return ret; } - typedef void (CDRomImpl::*CommandType)(); + typedef bool (CDRomImpl::*CommandType)(const QueueElement &, bool); const CommandType c_commandsHandlers[31] { #if 0 @@ -1045,40 +922,29 @@ class CDRomImpl final : public PCSX::CDRom { 0, 0, 0, // 28 }; - static constexpr std::chrono::nanoseconds c_commandsInitialDelay[31] = { - 0ns, 750us, 1ms, 0ns, // 0 - 0ns, 0ns, 1ms, 0ns, // 4 - 0ns, 1ms, 2ms, 750us, // 8 - 750us, 0ns, 750us, 0ns, // 12 - 750us, 750us, 0ns, 2ms, // 16 - 750us, 1ms, 1ms, 0ns, // 20 - 0ns, 750us, 5ms, 1ms, // 24 - 0ns, 0ns, 0ns, // 28 - }; - - void logCDROM(uint8_t command) { + void logCDROM(const QueueElement &command) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; - switch (command & 0xff) { + switch (command.value) { case CdlTest: PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlTest %02x\n", regs.pc, - regs.cycle, m_paramFIFO[0]); + regs.cycle, command.payload[0]); break; case CdlSetLoc: PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlSetloc %02x:%02x:%02x\n", - regs.pc, regs.cycle, m_paramFIFO[0], m_paramFIFO[1], m_paramFIFO[2]); + regs.pc, regs.cycle, command.payload[0], command.payload[1], command.payload[2]); break; case CdlPlay: PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlPlay %i\n", regs.pc, - regs.cycle, m_paramFIFO[0]); + regs.cycle, command.payload[0]); break; case CdlSetFilter: PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlSetfilter file: %i, channel: %i\n", regs.pc, - regs.cycle, m_paramFIFO[0], m_paramFIFO[1]); + regs.cycle, command.payload[0], command.payload[1]); break; case CdlSetMode: { - auto mode = m_paramFIFO[0]; + auto mode = command.payload[0]; std::string modeDecode = mode & 1 ? "CDDA" : "DATA"; if (mode & 2) modeDecode += " Autopause"; if (mode & 4) modeDecode += " Report"; @@ -1100,25 +966,25 @@ class CDRomImpl final : public PCSX::CDRom { if (mode & 0x40) modeDecode += " RealTimePlay"; modeDecode += mode & 0x80 ? " @2x" : " @1x"; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlSetmode %02x (%s)\n", - regs.pc, regs.cycle, m_paramFIFO[0], modeDecode); + regs.pc, regs.cycle, command.payload[0], modeDecode); } break; case CdlGetTN: PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlGetTN (returns %i)\n", regs.pc, regs.cycle, m_iso->getTN()); break; case CdlGetTD: { - auto ret = m_iso->getTD(m_paramFIFO[0]); + auto ret = m_iso->getTD(command.payload[0]); PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlGetTD %i (returns %02i:%02i:%02i)\n", regs.pc, - regs.cycle, m_paramFIFO[0], ret.m, ret.s, ret.f); + regs.cycle, command.payload[0], ret.m, ret.s, ret.f); } break; default: - if ((command & 0xff) > c_cdCmdEnumCount) { + if (command.value > c_cdCmdEnumCount) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: CdlUnknown(0x%02X)\n", - regs.pc, regs.cycle, command & 0xff); + regs.pc, regs.cycle, command.value); } else { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: %s\n", regs.pc, regs.cycle, - magic_enum::enum_names()[command & 0xff]); + magic_enum::enum_names()[command.value]); } break; } diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 9d4016142..89be1a33f 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -21,6 +21,7 @@ #include #include +#include #include "cdrom/cdriso.h" #include "cdrom/iec-60908b.h" @@ -38,15 +39,9 @@ namespace Widgets { class IsoBrowser; } -struct CdrStat { - uint32_t Type; - uint32_t Status; - IEC60908b::MSF Time; -}; - class CDRom { public: - using MSF = PCSX::IEC60908b::MSF; + using MSF = IEC60908b::MSF; CDRom() : m_iso(new CDRIso()) {} virtual ~CDRom() {} static CDRom* factory(); @@ -104,8 +99,6 @@ class CDRom { friend SaveStates::SaveState SaveStates::constructSaveState(); bool dataFIFOHasData() { return m_dataFIFOIndex != m_dataFIFOSize; } - bool paramFIFOAvailable() { return m_paramFIFOSize != 16; } - bool responseFIFOHasData() { return m_responseFIFOIndex != m_responseFIFOSize; } bool m_lidOpen = false; bool m_wasLidOpened = false; @@ -114,19 +107,10 @@ class CDRom { // to save/init uint8_t m_dataFIFO[2352] = {0}; - uint8_t m_paramFIFO[16] = {0}; - uint8_t m_responseFIFO[16] = {0}; uint32_t m_dataFIFOIndex = 0; uint32_t m_dataFIFOSize = 0; uint32_t m_dataFIFOPending = 0; - uint8_t m_paramFIFOSize = 0; - uint8_t m_responseFIFOIndex = 0; - uint8_t m_responseFIFOSize = 0; uint8_t m_registerIndex = 0; - bool m_errorArgumentsCount = false; - bool m_busy = false; - bool m_gotAck = false; - bool m_waitingAck = false; bool m_motorOn = false; bool m_speedChanged = false; bool m_invalidLocL = false; @@ -146,8 +130,6 @@ class CDRom { Seeking, PlayingCDDA, } m_status = Status::Idle; - uint8_t m_state = 0; - uint8_t m_command = 0; enum class Speed : uint8_t { Simple, Double } m_speed; enum class ReadSpan : uint8_t { S2048, S2328, S2340 } m_readSpan; uint8_t m_causeMask = 0x1f; @@ -159,13 +141,62 @@ class CDRom { Acknowledge = 3, End = 4, Error = 5, - } m_cause = Cause::None; + }; MSF m_currentPosition; MSF m_seekPosition; uint8_t m_lastLocP[8] = {0}; uint8_t m_lastLocL[8] = {0}; - unsigned m_readDelayed = 0; + + struct QueueElement { + uint8_t value; + uint8_t payload[16]; + bool valueRead = false; + bool hasValue = false; + uint8_t payloadSize = 0; + uint8_t payloadIndex = 0; + bool isPayloadEmpty() const { return payloadSize == payloadIndex; } + bool isPayloadFull() const { return payloadSize == sizeof(payload); } + bool empty() const { return (!hasValue || valueRead) && isPayloadEmpty(); } + void clear() { + hasValue = false; + valueRead = false; + payloadSize = 0; + payloadIndex = 0; + } + void setValue(uint8_t newValue) { + value = newValue; + hasValue = true; + } + void setValue(Cause cause) { setValue(static_cast(cause)); } + void pushPayloadData(uint8_t value) { + if (payloadSize < sizeof(payload)) payload[payloadSize++] = value; + } + void pushPayloadData(std::string_view values) { + for (auto value : values) { + pushPayloadData(value); + } + } + uint8_t getValue() const { return valueRead ? 0 : value; } + uint8_t readPayloadByte() { + if (payloadIndex < payloadSize) { + return payload[payloadIndex++]; + } + return 0; + } + }; + + QueueElement m_commandFifo; + QueueElement m_commandExecuting; + QueueElement m_responseFifo[2]; + bool responseFifoFull() { return !m_responseFifo[0].empty() && !m_responseFifo[1].empty(); } + void maybeEnqueueResponse(QueueElement& response) { + if (m_responseFifo[0].empty()) { + m_responseFifo[0] = response; + } else if (m_responseFifo[1].empty()) { + m_responseFifo[1] = response; + } + } private: friend class Widgets::IsoBrowser; diff --git a/src/core/r3000a.h b/src/core/r3000a.h index af4917089..aa0de32e9 100644 --- a/src/core/r3000a.h +++ b/src/core/r3000a.h @@ -316,6 +316,11 @@ class R3000Acpu { m_regs.scheduleMask &= ~(1 << s); } + bool isScheduled(Schedule s_) { + unsigned s = static_cast(s_); + return (m_regs.scheduleMask & (1 << s)) != 0; + } + psxRegisters m_regs; float m_scheduleScales[15] = {1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}; diff --git a/src/core/sstate.cc b/src/core/sstate.cc index 1b0b5d505..198401221 100644 --- a/src/core/sstate.cc +++ b/src/core/sstate.cc @@ -113,17 +113,6 @@ PCSX::SaveStates::SaveState PCSX::SaveStates::constructSaveState() { CallStacks{}, CDRom{ CDDataFIFO{g_emulator->m_cdrom->m_dataFIFO}, - CDParamFIFO{g_emulator->m_cdrom->m_paramFIFO}, - CDResponseFIFO{g_emulator->m_cdrom->m_responseFIFO}, - CDDataFIFOIndex{g_emulator->m_cdrom->m_dataFIFOIndex}, - CDDataFIFOSize{g_emulator->m_cdrom->m_dataFIFOSize}, - CDParamFIFOSize{g_emulator->m_cdrom->m_paramFIFOSize}, - CDResponseFIFOData{g_emulator->m_cdrom->m_responseFIFOIndex}, - CDResponseFIFOSize{g_emulator->m_cdrom->m_responseFIFOSize}, - CDRegisterIndex{g_emulator->m_cdrom->m_registerIndex}, - CDBusy{g_emulator->m_cdrom->m_busy}, - CDState{g_emulator->m_cdrom->m_state}, - CDCommand{g_emulator->m_cdrom->m_command}, }, }; } diff --git a/src/core/sstate.h b/src/core/sstate.h index 8500a1d48..9215533f4 100644 --- a/src/core/sstate.h +++ b/src/core/sstate.h @@ -248,10 +248,7 @@ typedef Protobuf::FieldRef CDRe typedef Protobuf::FieldRef CDBusy; typedef Protobuf::FieldRef CDState; typedef Protobuf::FieldRef CDCommand; -typedef Protobuf::Message - CDRom; +typedef Protobuf::Message CDRom; typedef Protobuf::MessageField CDRomField; typedef Protobuf::Message Date: Tue, 10 Jan 2023 07:42:34 -0800 Subject: [PATCH 136/185] Tests start passing again. --- src/core/cdrom.cc | 34 ++++++++++++++++++++++------------ src/core/cdrom.h | 4 +++- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 6cd481947..cb3d48548 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -106,7 +106,14 @@ class CDRomImpl final : public PCSX::CDRom { m_responseFifo[1].clear(); } - void fifoScheduledCallback() override { maybeStartCommand(); } + void fifoScheduledCallback() override { + if (m_responseFifo[0].empty() && !m_responseFifo[1].empty()) { + m_responseFifo[0] = m_responseFifo[1]; + m_responseFifo[1].clear(); + psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + } + maybeStartCommand(); + } void commandsScheduledCallback() override { auto command = m_commandExecuting.value; @@ -210,8 +217,7 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t bit = 1 << (causeValue - 1); if (m_causeMask & bit) { element.setValue(cause); - maybeEnqueueResponse(element); - psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + if (maybeEnqueueResponse(element)) psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); const bool debug = PCSX::g_emulator->settings.get() .get(); if (debug) { @@ -270,7 +276,9 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t read1() override { uint8_t ret = m_responseFifo[0].readPayloadByte(); - // TODO: if empty, move response FIFO and maybe trigger IRQ. + if (m_responseFifo[0].empty() && !m_responseFifo[1].empty()) { + scheduleFifo(1ms); + } const bool debug = PCSX::g_emulator->settings.get() .get(); @@ -431,7 +439,9 @@ class CDRomImpl final : public PCSX::CDRom { } if (ack) { m_responseFifo[0].valueRead = true; - // TODO: if empty, move response FIFO and maybe trigger IRQ. + if (m_responseFifo[0].empty() && !m_responseFifo[1].empty()) { + scheduleFifo(1ms); + } return; } if (value & 0x10) { @@ -490,30 +500,30 @@ class CDRomImpl final : public PCSX::CDRom { } void maybeStartCommand() { + if (m_commandFifo.empty()) return; auto command = m_commandFifo.value; static constexpr unsigned c_commandMax = sizeof(c_commandsArgumentsCount) / sizeof(c_commandsArgumentsCount[0]); if (command >= c_commandMax) { maybeEnqueueError(1, 0x40); endCommand(); + m_commandFifo.clear(); return; } auto expectedCount = c_commandsArgumentsCount[command]; if ((expectedCount >= 0) && (expectedCount != m_commandFifo.payloadSize)) { maybeEnqueueError(1, 0x20); endCommand(); + m_commandFifo.clear(); return; } auto handler = c_commandsHandlers[command]; if (handler) { - if ((this->*handler)(m_commandFifo, true)) { - m_commandExecuting = m_commandFifo; - } - m_commandFifo.clear(); + if ((this->*handler)(m_commandFifo, true)) m_commandExecuting = m_commandFifo; } else { maybeEnqueueError(1, 0x40); endCommand(); - return; } + m_commandFifo.clear(); } void endCommand() { @@ -615,6 +625,8 @@ class CDRomImpl final : public PCSX::CDRom { bool cdlInit(const QueueElement &command, bool start) { if (start) { QueueElement response; + m_motorOn = true; + m_speedChanged = false; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); schedule(120ms); @@ -622,8 +634,6 @@ class CDRomImpl final : public PCSX::CDRom { } else { // TODO: figure out exactly the various states of the CD-Rom controller // that are being reset, and their value. - m_motorOn = true; - m_speedChanged = false; m_currentPosition.reset(); m_currentPosition.s = 2; m_seekPosition.reset(); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 89be1a33f..839debaa0 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -190,12 +190,14 @@ class CDRom { QueueElement m_commandExecuting; QueueElement m_responseFifo[2]; bool responseFifoFull() { return !m_responseFifo[0].empty() && !m_responseFifo[1].empty(); } - void maybeEnqueueResponse(QueueElement& response) { + bool maybeEnqueueResponse(QueueElement& response) { if (m_responseFifo[0].empty()) { m_responseFifo[0] = response; + return true; } else if (m_responseFifo[1].empty()) { m_responseFifo[1] = response; } + return false; } private: From 3bf7e0bf3b41c141cae103967703ce6ecdc6829e Mon Sep 17 00:00:00 2001 From: Nicolas 'Pixel' Noble Date: Tue, 10 Jan 2023 18:24:03 -0800 Subject: [PATCH 137/185] Derp. --- src/mips/tests/cdrom/cdlseekp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/cdlseekp.c b/src/mips/tests/cdrom/cdlseekp.c index 9b4c3025f..411607425 100644 --- a/src/mips/tests/cdrom/cdlseekp.c +++ b/src/mips/tests/cdrom/cdlseekp.c @@ -355,7 +355,7 @@ CESTER_TEST(cdlSeekP2to85AndNop, test_instance, CDROM_REG0 = 0; CDROM_REG1 = CDL_SEEKP; - while (CDROM_REG0 & 0x85); + while (CDROM_REG0 & 0x80); CDROM_REG1 = CDL_NOP; uint32_t ackTime = waitCDRomIRQ(); From 0ccc5149d698dfc843171b36cd5a4e13cdff71e1 Mon Sep 17 00:00:00 2001 From: Nicolas 'Pixel' Noble Date: Tue, 10 Jan 2023 18:24:22 -0800 Subject: [PATCH 138/185] More tests passing. --- src/core/cdrom.cc | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index cb3d48548..9cc1bc4f6 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -609,10 +609,10 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); - return true; - } else { m_status = Status::Idle; m_invalidLocL = true; + return true; + } else { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Complete, response); @@ -630,8 +630,6 @@ class CDRomImpl final : public PCSX::CDRom { response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); schedule(120ms); - return true; - } else { // TODO: figure out exactly the various states of the CD-Rom controller // that are being reset, and their value. m_currentPosition.reset(); @@ -643,6 +641,8 @@ class CDRomImpl final : public PCSX::CDRom { m_status = Status::Idle; m_causeMask = 0x1f; memset(m_lastLocP, 0, sizeof(m_lastLocP)); + return true; + } else { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Complete, response); @@ -783,6 +783,9 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); + schedule(15ms); + return true; + } else if (m_status != Status::Seeking) { auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); if (m_speedChanged) { m_speedChanged = false; @@ -816,6 +819,9 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); + schedule(15ms); + return true; + } else if (m_status != Status::Seeking) { auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::CDDA); if (m_speedChanged) { m_speedChanged = false; From b3f9aac2f155fab36b8ba554fdde79764d963fe9 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 10 Jan 2023 19:15:14 -0800 Subject: [PATCH 139/185] Adding reading-init test. --- src/mips/tests/cdrom/reading.c | 97 ++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 493ba9f4e..4b0fbd2dc 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -294,6 +294,103 @@ CESTER_TEST(simpleReadingWithoutAck, test_instances, ramsyscall_printf("Long read, ack then pause, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); ) +CESTER_TEST(simpleReadingWithoutAckThenInit, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0x20, 0, 0); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + waitCDRomIRQ(); + ackCDRomCause(); + + initializeTime(); + while (updateTime() <= 500000); + + initializeTime(); + uint32_t time1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_INIT; + + initializeTime(); + uint32_t time3 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time4 = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(1, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(0x22, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize3); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + ramsyscall_printf("Long read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); +) + CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, int resetDone = resetCDRom(); if (!resetDone) { From e5a83ea2dd07d36e13b3ba585df6918c19d7a26e Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 10 Jan 2023 20:17:09 -0800 Subject: [PATCH 140/185] Making test less flaky. --- src/mips/tests/cdrom/race.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index dec6f1f57..917af8269 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -289,7 +289,7 @@ CESTER_TEST(raceSeekP2to85AckWaitAndNop, test_instance, ramsyscall_printf("SeekP from 00:02:00 to 85:00:00 with Nop in between: ack in %ius, ack2 in %ius, errored in %ius\n", ackTime, ackTime2, errorTime); ) -CESTER_TEST(raceSeekP2to85WaitAckAndNop, test_instance, +CESTER_TEST(raceSeekL2to71WaitAckAndNop, test_instance, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -302,7 +302,7 @@ CESTER_TEST(raceSeekP2to85WaitAckAndNop, test_instance, return; } - int setLocDone = setLoc(0x85, 0, 0); + int setLocDone = setLoc(0x71, 0, 0); if (!setLocDone) { cester_assert_true(setLocDone); return; @@ -314,7 +314,7 @@ CESTER_TEST(raceSeekP2to85WaitAckAndNop, test_instance, initializeTime(); CDROM_REG0 = 0; - CDROM_REG1 = CDL_SEEKP; + CDROM_REG1 = CDL_SEEKL; uint8_t ctrl0 = CDROM_REG0 & ~3; while (CDROM_REG0 & 0x80); @@ -323,9 +323,9 @@ CESTER_TEST(raceSeekP2to85WaitAckAndNop, test_instance, uint8_t ctrl0b = CDROM_REG0 & ~3; initializeTime(); - // Wait 10s... - ramsyscall_printf("Waiting 6s...\n"); - while (updateTime() < 6000000); + // Wait 2s... + ramsyscall_printf("Waiting 2s...\n"); + while (updateTime() < 2000000); ramsyscall_printf("Done...\n"); initializeTime(); @@ -357,7 +357,7 @@ CESTER_TEST(raceSeekP2to85WaitAckAndNop, test_instance, cester_assert_uint_eq(0xe0, cause2b); cester_assert_uint_eq(2, response1[0]); cester_assert_uint_eq(1, responseSize1); - cester_assert_uint_eq(0, response2[0]); + cester_assert_uint_eq(0x42, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x98, ctrl0); cester_assert_uint_eq(0xb8, ctrl0b); @@ -370,7 +370,7 @@ CESTER_TEST(raceSeekP2to85WaitAckAndNop, test_instance, cester_assert_uint_lt(ackTime, 150); cester_assert_uint_ge(ackTime2, 500); cester_assert_uint_lt(ackTime2, 7000); - ramsyscall_printf("SeekP from 00:02:00 to 85:00:00 then stall with Nop: ack in %ius, ack2 in %ius\n", ackTime, ackTime2); + ramsyscall_printf("SeekL from 00:02:00 to 71:00:00 then stall with Nop: ack in %ius, ack2 in %ius\n", ackTime, ackTime2); ) CESTER_TEST(raceNopWaitAndNop, test_instances, From da48ab85b39cbad21df73838144c7e983428dcee Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 10 Jan 2023 21:43:17 -0800 Subject: [PATCH 141/185] Making sure we're properly timeouting on this seek test. --- src/mips/tests/cdrom/race.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 917af8269..4c8726a31 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -348,7 +348,7 @@ CESTER_TEST(raceSeekL2to71WaitAckAndNop, test_instance, CDROM_REG0 = 1; uint8_t cause2b = CDROM_REG3_UC; - uint32_t timeout = 150000; + uint32_t timeout = 1500000; int gotIRQ = waitCDRomIRQWithTimeout(&timeout); cester_assert_uint_eq(3, cause1); From 92969d732f3ff06312b64c710ca177e9ec69adc7 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 10 Jan 2023 23:35:31 -0800 Subject: [PATCH 142/185] Fixing a few more tests. --- src/core/cdrom.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 9cc1bc4f6..cde1602d2 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -259,7 +259,7 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t adpcmPlaying = 0; uint8_t v3 = m_commandFifo.isPayloadEmpty() ? 0x08 : 0; uint8_t v4 = !m_commandFifo.isPayloadFull() ? 0x10 : 0; - uint8_t v5 = !m_responseFifo[0].empty() ? 0x20 : 0; + uint8_t v5 = !m_responseFifo[0].isPayloadEmpty() ? 0x20 : 0; uint8_t v6 = m_dataFIFOSize != m_dataFIFOIndex ? 0x40 : 0; uint8_t v7 = m_commandFifo.hasValue ? 0x80 : 0; From e1ba35af18a4b8b5ecd9ececee1942adf77398dd Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 10 Jan 2023 23:35:43 -0800 Subject: [PATCH 143/185] Better naming / logic. --- src/core/cdrom.cc | 52 ++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 28 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index cde1602d2..6ebd71400 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -276,9 +276,7 @@ class CDRomImpl final : public PCSX::CDRom { uint8_t read1() override { uint8_t ret = m_responseFifo[0].readPayloadByte(); - if (m_responseFifo[0].empty() && !m_responseFifo[1].empty()) { - scheduleFifo(1ms); - } + maybeScheduleNextCommand(); const bool debug = PCSX::g_emulator->settings.get() .get(); @@ -439,9 +437,7 @@ class CDRomImpl final : public PCSX::CDRom { } if (ack) { m_responseFifo[0].valueRead = true; - if (m_responseFifo[0].empty() && !m_responseFifo[1].empty()) { - scheduleFifo(1ms); - } + maybeScheduleNextCommand(); return; } if (value & 0x10) { @@ -505,14 +501,14 @@ class CDRomImpl final : public PCSX::CDRom { static constexpr unsigned c_commandMax = sizeof(c_commandsArgumentsCount) / sizeof(c_commandsArgumentsCount[0]); if (command >= c_commandMax) { maybeEnqueueError(1, 0x40); - endCommand(); + maybeScheduleNextCommand(); m_commandFifo.clear(); return; } auto expectedCount = c_commandsArgumentsCount[command]; if ((expectedCount >= 0) && (expectedCount != m_commandFifo.payloadSize)) { maybeEnqueueError(1, 0x20); - endCommand(); + maybeScheduleNextCommand(); m_commandFifo.clear(); return; } @@ -521,13 +517,13 @@ class CDRomImpl final : public PCSX::CDRom { if ((this->*handler)(m_commandFifo, true)) m_commandExecuting = m_commandFifo; } else { maybeEnqueueError(1, 0x40); - endCommand(); + maybeScheduleNextCommand(); } m_commandFifo.clear(); } - void endCommand() { - if (!responseFifoFull() && !m_commandFifo.empty()) scheduleFifo(1ms); + void maybeScheduleNextCommand() { + if (!responseFifoFull()) scheduleFifo(1ms); } enum class SeekType { DATA, CDDA }; @@ -556,7 +552,7 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus(true)); maybeTriggerIRQ(Cause::Acknowledge, response); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -576,7 +572,7 @@ class CDRomImpl final : public PCSX::CDRom { } else { maybeEnqueueError(1, 0x10); } - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -594,7 +590,7 @@ class CDRomImpl final : public PCSX::CDRom { m_startReading = true; m_readingType = ReadingType::Normal; maybeTriggerIRQ(Cause::Acknowledge, response); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -616,7 +612,7 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Complete, response); - endCommand(); + maybeScheduleNextCommand(); return false; } } @@ -646,7 +642,7 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Complete, response); - endCommand(); + maybeScheduleNextCommand(); return false; } } @@ -659,7 +655,7 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -671,7 +667,7 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -714,7 +710,7 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -729,7 +725,7 @@ class CDRomImpl final : public PCSX::CDRom { response.pushPayloadData(std::string_view((char *)m_lastLocL, sizeof(m_lastLocL))); maybeTriggerIRQ(Cause::Acknowledge, response); } - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -741,7 +737,7 @@ class CDRomImpl final : public PCSX::CDRom { QueueElement response; response.pushPayloadData(std::string_view((char *)m_lastLocP, sizeof(m_lastLocP))); maybeTriggerIRQ(Cause::Acknowledge, response); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -754,7 +750,7 @@ class CDRomImpl final : public PCSX::CDRom { response.pushPayloadData(1); response.pushPayloadData(PCSX::IEC60908b::itob(m_iso->getTN())); maybeTriggerIRQ(Cause::Acknowledge, response); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -773,7 +769,7 @@ class CDRomImpl final : public PCSX::CDRom { response.pushPayloadData(PCSX::IEC60908b::itob(td.s)); maybeTriggerIRQ(Cause::Acknowledge, response); } - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -808,7 +804,7 @@ class CDRomImpl final : public PCSX::CDRom { maybeTriggerIRQ(Cause::Complete, response); } m_invalidLocL = true; - endCommand(); + maybeScheduleNextCommand(); return false; } } @@ -842,7 +838,7 @@ class CDRomImpl final : public PCSX::CDRom { maybeTriggerIRQ(Cause::Complete, response); } m_invalidLocL = true; - endCommand(); + maybeScheduleNextCommand(); return false; } } @@ -852,7 +848,7 @@ class CDRomImpl final : public PCSX::CDRom { static constexpr uint8_t c_test20[] = {0x94, 0x09, 0x19, 0xc0}; if (command.isPayloadEmpty()) { maybeEnqueueError(1, 0x20); - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -870,7 +866,7 @@ class CDRomImpl final : public PCSX::CDRom { maybeEnqueueError(1, 0x10); break; } - endCommand(); + maybeScheduleNextCommand(); return false; } @@ -891,7 +887,7 @@ class CDRomImpl final : public PCSX::CDRom { response.pushPayloadData(0x00); response.pushPayloadData("PCSX"sv); maybeTriggerIRQ(Cause::Complete, response); - endCommand(); + maybeScheduleNextCommand(); return false; } } From 9d7529d18402e144c93e3e3d55e6742c2bc87494 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 12 Jan 2023 19:37:08 -0800 Subject: [PATCH 144/185] Better determinicity for the read tests, and adding a couple more. --- src/mips/tests/cdrom/reading.c | 143 +++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 34 deletions(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 4b0fbd2dc..c93fa87e8 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -39,10 +39,10 @@ CESTER_TEST(simpleReading, test_instances, return; } - int setLocDone = setLoc(0x20, 2, 0); + int seekDone = seekLTo(0x20, 2, 0); - if (!setLocDone) { - cester_assert_true(setLocDone); + if (!seekDone) { + cester_assert_true(seekDone); return; } @@ -123,10 +123,11 @@ CESTER_TEST(setLocDuringSimpleReading, test_instances, return; } - int setLocDone = setLoc(0x20, 2, 0); + int seekDone = seekLTo(0x20, 2, 0); + int setLocDone = 0; - if (!setLocDone) { - cester_assert_true(setLocDone); + if (!seekDone) { + cester_assert_true(seekDone); return; } @@ -194,7 +195,7 @@ CESTER_TEST(setLocDuringSimpleReading, test_instances, cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(3, cause2); cester_assert_uint_eq(2, cause3); - cester_assert_true(setLocDone); + cester_assert_true(seekDone); ) CESTER_TEST(simpleReadingWithoutAck, test_instances, @@ -210,9 +211,9 @@ CESTER_TEST(simpleReadingWithoutAck, test_instances, return; } - int setLocDone = setLoc(0x20, 0, 0); - if (!setLocDone) { - cester_assert_true(setLocDone); + int seekDone = seekLTo(0x20, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); return; } @@ -307,9 +308,9 @@ CESTER_TEST(simpleReadingWithoutAckThenInit, test_instances, return; } - int setLocDone = setLoc(0x20, 0, 0); - if (!setLocDone) { - cester_assert_true(setLocDone); + int seekDone = seekLTo(0x20, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); return; } @@ -404,9 +405,9 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, return; } - int setLocDone = setLoc(0x20, 0, 0); - if (!setLocDone) { - cester_assert_true(setLocDone); + int seekDone = seekLTo(0x20, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); return; } @@ -421,6 +422,80 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, CDROM_REG0 = 0; CDROM_REG1 = CDL_PAUSE; + unsigned readyCount = 0; + uint32_t time1; + uint8_t cause1; + uint8_t ctrl1, ctrl2; + uint8_t response1[16]; + uint8_t responseSize1; + while (1) { + initializeTime(); + time1 = waitCDRomIRQ(); + cause1 = ackCDRomCause(); + ctrl1 = CDROM_REG0 & ~3; + responseSize1 = readResponse(response1); + ctrl2 = CDROM_REG0 & ~3; + if (cause1 == 1) { + readyCount++; + } else { + break; + } + } + + initializeTime(); + uint32_t time2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x22, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_ge(readyCount, 1); + cester_assert_uint_le(readyCount, 2); + ramsyscall_printf("Long read, pause then ack, ack in %ius, complete in %ius\n", time1, time2); +) + +CESTER_TEST(simpleReadingNopQuery, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int seekDone = seekLTo(0x20, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + waitCDRomIRQ(); + ackCDRomCause(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + initializeTime(); uint32_t time1 = waitCDRomIRQ(); uint8_t cause1 = ackCDRomCause(); @@ -464,7 +539,7 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, CDROM_REG0 = 1; uint8_t cause4b = CDROM_REG3_UC; - cester_assert_uint_eq(5, cause1); + cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(1, cause2); cester_assert_uint_eq(0xe0, cause2b); @@ -480,21 +555,18 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, cester_assert_uint_eq(0x18, ctrl6); cester_assert_uint_eq(0x38, ctrl7); cester_assert_uint_eq(0x18, ctrl8); - // This bit will jitter - uint8_t response1_0 = response1[0] & ~0x40; - cester_assert_uint_eq(3, response1_0); - cester_assert_uint_eq(0x80, response1[1]); - cester_assert_uint_eq(2, responseSize1); - cester_assert_uint_eq(0x23, response2[0]); + cester_assert_uint_eq(0x42, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, pause then ack, error in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, nop then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); ) -CESTER_TEST(simpleReadingNopQuery, test_instances, +CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -507,9 +579,9 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, return; } - int setLocDone = setLoc(0x20, 0, 0); - if (!setLocDone) { - cester_assert_true(setLocDone); + int seekDone = seekLTo(0x20, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); return; } @@ -523,10 +595,13 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, for (unsigned i = 0; i < 100; i++) { CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; - waitCDRomIRQ(); - ackCDRomCause(); - uint8_t response[16]; - readResponse(response); + uint8_t cause; + do { + waitCDRomIRQ(); + cause = ackCDRomCause(); + uint8_t response[16]; + readResponse(response); + } while (cause == 1); } CDROM_REG0 = 0; @@ -591,7 +666,7 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, cester_assert_uint_eq(0x18, ctrl6); cester_assert_uint_eq(0x38, ctrl7); cester_assert_uint_eq(0x18, ctrl8); - cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(0x22, response1[0]); cester_assert_uint_eq(1, responseSize1); cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); @@ -599,5 +674,5 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, nop then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, nop series then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); ) From dfb6d45fdaffc71575242e19e7875e192c904fd7 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 23 Jan 2023 20:41:53 -0800 Subject: [PATCH 145/185] Forgot to read one response, but also, we need more tests... --- src/mips/tests/cdrom/reading.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index c93fa87e8..043e6990a 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -221,6 +221,8 @@ CESTER_TEST(simpleReadingWithoutAck, test_instances, CDROM_REG1 = CDL_READN; waitCDRomIRQ(); ackCDRomCause(); + uint8_t response[16]; + readResponse(response); initializeTime(); while (updateTime() <= 500000); From ec27f98d0191d2cdc0415973dff1b4e520a040c2 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 23 Jan 2023 21:16:00 -0800 Subject: [PATCH 146/185] Fixing a few more tests, and actually adding the extra one needed here. --- src/mips/tests/cdrom/reading.c | 105 +++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 043e6990a..2e7a24232 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -297,6 +297,103 @@ CESTER_TEST(simpleReadingWithoutAck, test_instances, ramsyscall_printf("Long read, ack then pause, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); ) +CESTER_SKIP_TEST(simpleReadingWithoutAckNorResponseReadThenInit, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int seekDone = seekLTo(0x20, 0, 0); + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + waitCDRomIRQ(); + ackCDRomCause(); + + initializeTime(); + while (updateTime() <= 500000); + + initializeTime(); + uint32_t time1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time2 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_INIT; + + initializeTime(); + uint32_t time3 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + initializeTime(); + uint32_t time4 = waitCDRomIRQ(); + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(1, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(0x22, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize3); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + ramsyscall_printf("Long read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); +) + CESTER_TEST(simpleReadingWithoutAckThenInit, test_instances, int resetDone = resetCDRom(); if (!resetDone) { @@ -320,6 +417,8 @@ CESTER_TEST(simpleReadingWithoutAckThenInit, test_instances, CDROM_REG1 = CDL_READN; waitCDRomIRQ(); ackCDRomCause(); + uint8_t response[16]; + readResponse(response); initializeTime(); while (updateTime() <= 500000); @@ -417,6 +516,8 @@ CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, CDROM_REG1 = CDL_READN; waitCDRomIRQ(); ackCDRomCause(); + uint8_t response[16]; + readResponse(response); initializeTime(); while (updateTime() <= 500000); @@ -493,6 +594,8 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, CDROM_REG1 = CDL_READN; waitCDRomIRQ(); ackCDRomCause(); + uint8_t response[16]; + readResponse(response); initializeTime(); CDROM_REG0 = 0; @@ -591,6 +694,8 @@ CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, CDROM_REG1 = CDL_READN; waitCDRomIRQ(); ackCDRomCause(); + uint8_t response[16]; + readResponse(response); initializeTime(); From ee670a0b2423cd8a9d13d026b385fb51939670d7 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 23 Jan 2023 21:32:47 -0800 Subject: [PATCH 147/185] Adjusting test message. --- src/mips/tests/cdrom/reading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 2e7a24232..0ddf2d88f 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -391,7 +391,7 @@ CESTER_SKIP_TEST(simpleReadingWithoutAckNorResponseReadThenInit, test_instances, cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, no response read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); ) CESTER_TEST(simpleReadingWithoutAckThenInit, test_instances, From 3b22b6514af1afaa5545e0747710260f872c2a79 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 23 Jan 2023 22:42:23 -0800 Subject: [PATCH 148/185] Derp. --- src/mips/tests/cdrom/reading.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 0ddf2d88f..c1287f9ce 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -294,7 +294,7 @@ CESTER_TEST(simpleReadingWithoutAck, test_instances, cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, ack then pause, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, ack then pause, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); ) CESTER_SKIP_TEST(simpleReadingWithoutAckNorResponseReadThenInit, test_instances, @@ -391,7 +391,7 @@ CESTER_SKIP_TEST(simpleReadingWithoutAckNorResponseReadThenInit, test_instances, cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, no response read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, no response read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); ) CESTER_TEST(simpleReadingWithoutAckThenInit, test_instances, @@ -490,7 +490,7 @@ CESTER_TEST(simpleReadingWithoutAckThenInit, test_instances, cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, ack then init, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); ) CESTER_TEST(simpleReadingPauseWithoutAck, test_instances, @@ -668,7 +668,7 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, nop then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, nop then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); ) CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, @@ -781,5 +781,5 @@ CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, cester_assert_uint_eq(1, responseSize3); cester_assert_uint_eq(2, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, nop series then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time3); + ramsyscall_printf("Long read, nop series then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); ) From b6da9bf613a660f327291b5af0d0a5eff3acc95e Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 24 Jan 2023 20:16:38 -0800 Subject: [PATCH 149/185] Only a few failed tests left... --- src/core/cdrom.cc | 14 ++++++++++---- src/core/cdrom.h | 1 + 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 6ebd71400..6f104429c 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -87,7 +87,13 @@ class CDRomImpl final : public PCSX::CDRom { return PCSX::IEC60908b::MSF(m, s, f); } + uint32_t rand() { + m_seed *= 14726776315600504853ull; + return m_seed >> 9; + } + void reset() override { + m_seed = 9223521712174600777ull; m_dataFIFOIndex = 0; m_dataFIFOSize = 0; m_registerIndex = 0; @@ -352,7 +358,7 @@ class CDRomImpl final : public PCSX::CDRom { .get()) { logCDROM(m_commandFifo); } - scheduleFifo(1ms); + scheduleFifo(797us); } m_commandFifo.hasValue = true; break; @@ -496,7 +502,7 @@ class CDRomImpl final : public PCSX::CDRom { } void maybeStartCommand() { - if (m_commandFifo.empty()) return; + if (m_commandFifo.empty() || !m_responseFifo[1].empty()) return; auto command = m_commandFifo.value; static constexpr unsigned c_commandMax = sizeof(c_commandsArgumentsCount) / sizeof(c_commandsArgumentsCount[0]); if (command >= c_commandMax) { @@ -523,7 +529,7 @@ class CDRomImpl final : public PCSX::CDRom { } void maybeScheduleNextCommand() { - if (!responseFifoFull()) scheduleFifo(1ms); + if (!responseFifoFull()) scheduleFifo(797us); } enum class SeekType { DATA, CDDA }; @@ -542,7 +548,7 @@ class CDRomImpl final : public PCSX::CDRom { } // TODO: ought to be a decent approximation for now, // but may require some tuning later on. - return std::chrono::microseconds(distance * 3) + 150ms; + return std::chrono::microseconds(distance * 3) + 167ms; } std::chrono::nanoseconds computeReadDelay() { return m_speed == Speed::Simple ? 13333us : 6666us; } diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 839debaa0..576975a21 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -106,6 +106,7 @@ class CDRom { uint32_t m_lidCloseAtCycles = 0; // to save/init + uint64_t m_seed = 9223521712174600777ull; uint8_t m_dataFIFO[2352] = {0}; uint32_t m_dataFIFOIndex = 0; uint32_t m_dataFIFOSize = 0; From 63f0f2508f007d6dccf3f6b10dec6086bb8f3e85 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 5 Mar 2023 15:03:25 -0800 Subject: [PATCH 150/185] Adding test for flag changes in read. --- src/mips/tests/cdrom/reading.c | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index c1287f9ce..826699b3b 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -783,3 +783,81 @@ CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, cester_assert_uint_eq(1, responseSize4); ramsyscall_printf("Long read, nop series then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); ) + +CESTER_TEST(simpleReadingNoSeekNopQueries, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setLocDone = setLoc(0x60, 0x02, 0x00); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t time1 = waitCDRomIRQ(); + ackCDRomCause(); + uint8_t response[16]; + readResponse(response); + + uint8_t runningCause; + uint8_t responses[32]; + uint32_t times[32]; + int32_t lastResponse = -1; + unsigned responseCount = 0; + + do { + CDROM_REG0 = 0; + CDROM_REG1 = CDL_NOP; + uint32_t time = waitCDRomIRQ(); + runningCause = ackCDRomCause(); + uint8_t runningResponse[16]; + readResponse(runningResponse); + uint8_t r = runningResponse[0]; + if (r != lastResponse) { + responses[responseCount] = lastResponse = r; + times[responseCount] = time; + responseCount++; + } + } while(runningCause == 3); + + uint32_t time2 = waitCDRomIRQ(); + uint8_t cause = ackCDRomCause(); + uint8_t response2[16]; + readResponse(response2); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + + uint32_t time3 = waitCDRomIRQ(); + ackCDRomCause(); + uint8_t response3[16]; + readResponse(response3); + + uint32_t time4 = waitCDRomIRQ(); + ackCDRomCause(); + uint8_t response4[16]; + readResponse(response4); + + uint32_t dtime1 = times[0]; + uint32_t dtime2 = times[1] - times[0]; + uint32_t dtime3 = times[2] - times[1]; + + cester_assert_uint_eq(3, cause); + cester_assert_uint_eq(3, responseCount); + cester_assert_uint_eq(0x02, responses[0]); + cester_assert_uint_eq(0x42, responses[1]); + cester_assert_uint_eq(0x22, responses[2]); + cester_assert_uint_ge(dtime1, 2000); + cester_assert_uint_le(dtime1, 4000); + cester_assert_uint_ge(dtime2, 15000); + cester_assert_uint_le(dtime2, 50000); + cester_assert_uint_ge(dtime3, 700000); + cester_assert_uint_le(dtime3, 2000000); + ramsyscall_printf("Reading without seeking first, different nop count = %i, response1 = 0x%02x, dtime1 = %ius, response2 = 0x%02x, dtime2 = %ius, response3 = 0x%02x, dtime3 = %ius, time1 = %ius, time2 = %ius, time3 = %ius, time4 = %ius\n", responseCount, responses[0], dtime1, responses[1], dtime2, responses[2], dtime3, time1, time2, time3, time4); +) From b713abfe027385dddb8f37bfe3aadc550741a392 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 6 Mar 2023 22:51:15 -0800 Subject: [PATCH 151/185] Lowering threshold a bit. --- src/mips/tests/cdrom/reading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 826699b3b..c56b123b5 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -853,7 +853,7 @@ CESTER_TEST(simpleReadingNoSeekNopQueries, test_instances, cester_assert_uint_eq(0x02, responses[0]); cester_assert_uint_eq(0x42, responses[1]); cester_assert_uint_eq(0x22, responses[2]); - cester_assert_uint_ge(dtime1, 2000); + cester_assert_uint_ge(dtime1, 1500); cester_assert_uint_le(dtime1, 4000); cester_assert_uint_ge(dtime2, 15000); cester_assert_uint_le(dtime2, 50000); From 4bdc18aedd12b3870e9932ea19c2c1fdd7646eef Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 6 Mar 2023 22:51:53 -0800 Subject: [PATCH 152/185] Unskipping this test. --- src/mips/tests/cdrom/reading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index c56b123b5..33e4abe13 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -297,7 +297,7 @@ CESTER_TEST(simpleReadingWithoutAck, test_instances, ramsyscall_printf("Long read, ack then pause, ready1 in %ius, ready2 in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); ) -CESTER_SKIP_TEST(simpleReadingWithoutAckNorResponseReadThenInit, test_instances, +CESTER_TEST(simpleReadingWithoutAckNorResponseReadThenInit, test_instances, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); From cb8cb0e6bed45b34a79289d09b8ca62f612cf301 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 6 Mar 2023 22:52:11 -0800 Subject: [PATCH 153/185] Enabling pcsx hw for these tests. --- src/mips/tests/cdrom/cdrom.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index 0cbd95bd7..bc925fcd4 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -28,6 +28,7 @@ SOFTWARE. #include "common/hardware/dma.h" #include "common/hardware/hwregs.h" #include "common/hardware/irq.h" +#include "common/hardware/pcsxhw.h" #include "common/syscalls/syscalls.h" #undef unix From c95b5268e2ba595d62b3c633fc812c3e7368e5ca Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 6 Mar 2023 23:45:39 -0800 Subject: [PATCH 154/185] Adding missing check. --- src/mips/tests/cdrom/race.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mips/tests/cdrom/race.c b/src/mips/tests/cdrom/race.c index 4c8726a31..63e384c07 100644 --- a/src/mips/tests/cdrom/race.c +++ b/src/mips/tests/cdrom/race.c @@ -265,6 +265,7 @@ CESTER_TEST(raceSeekP2to85AckWaitAndNop, test_instance, cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(3, cause2); + cester_assert_uint_eq(5, cause3); cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(0xe0, cause2b); cester_assert_uint_eq(2, response1[0]); From 9ac714f7aed2e772049ced319251113bbe968c54 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 7 Mar 2023 22:10:10 -0800 Subject: [PATCH 155/185] Some more subtle changes, and getting almost all tests to pass now. --- src/core/cdrom.cc | 131 +++++++++++++++++++++++++++++++++++++++------- src/core/cdrom.h | 12 +---- 2 files changed, 114 insertions(+), 29 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 6f104429c..41f4cba71 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -113,10 +113,16 @@ class CDRomImpl final : public PCSX::CDRom { } void fifoScheduledCallback() override { - if (m_responseFifo[0].empty() && !m_responseFifo[1].empty()) { + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (m_responseFifo[0].valueEmpty() && !m_responseFifo[1].empty()) { m_responseFifo[0] = m_responseFifo[1]; m_responseFifo[1].clear(); psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + if (debug) { + PCSX::g_system->log(PCSX::LogClass::CDROM, + "CDRom: response fifo sliding one response, triggering IRQ.\n"); + } } maybeStartCommand(); } @@ -132,10 +138,22 @@ class CDRomImpl final : public PCSX::CDRom { const bool debug = PCSX::g_emulator->settings.get() .get(); if (m_startReading) { - m_startReading = false; - m_status = Status::ReadingData; - } - if ((m_status == Status::Idle) || (m_status == Status::Seeking)) { + if (m_status == Status::Idle) { + m_status = Status::Seeking; + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + m_status = Status::Seeking; + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; + } + m_currentPosition = m_seekPosition; + scheduleRead(seekDelay + computeReadDelay()); + return; + } else { + m_startReading = false; + m_status = Status::ReadingData; + } + } else if ((m_status == Status::Idle) || (m_status == Status::Seeking)) { m_readingType = ReadingType::None; if (debug) { PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: cancelling read.\n"); @@ -218,18 +236,43 @@ class CDRomImpl final : public PCSX::CDRom { void scheduleDMA(uint32_t cycles) { PCSX::g_emulator->m_cpu->schedule(PCSX::Schedule::CDRDMA, cycles); } void scheduleDMA(std::chrono::nanoseconds delay) { scheduleDMA(PCSX::psxRegisters::durationToCycles(delay)); } + bool maybeEnqueueResponse(QueueElement &response) { + if (m_responseFifo[0].valueEmpty() && !m_responseFifo[1].empty()) { + m_responseFifo[0] = m_responseFifo[1]; + m_responseFifo[1] = response; + return true; + } + if (m_responseFifo[0].empty()) { + m_responseFifo[0] = response; + return true; + } else if (m_responseFifo[1].empty()) { + m_responseFifo[1] = response; + } + return false; + } + void maybeTriggerIRQ(Cause cause, QueueElement &element) { uint8_t causeValue = static_cast(cause); uint8_t bit = 1 << (causeValue - 1); if (m_causeMask & bit) { element.setValue(cause); - if (maybeEnqueueResponse(element)) psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + bool actuallyTriggering = false; + if (maybeEnqueueResponse(element)) { + psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); + actuallyTriggering = true; + } const bool debug = PCSX::g_emulator->settings.get() .get(); if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] triggering IRQ with cause %d\n", regs.pc, - regs.cycle, causeValue); + if (actuallyTriggering) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] triggering IRQ with cause %d\n", + regs.pc, regs.cycle, causeValue); + } else { + PCSX::g_system->log(PCSX::LogClass::CDROM, + "CD-Rom: %08x.%08x] wanted to trigger IRQ with cause %d, but queue is full\n", + regs.pc, regs.cycle, causeValue); + } } } else { if (PCSX::g_emulator->settings.get() @@ -442,6 +485,10 @@ class CDRomImpl final : public PCSX::CDRom { ack = true; } if (ack) { + if (debug) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: acked %02x (was %i)\n", value, + m_responseFifo[0].value); + } m_responseFifo[0].valueRead = true; maybeScheduleNextCommand(); return; @@ -502,8 +549,49 @@ class CDRomImpl final : public PCSX::CDRom { } void maybeStartCommand() { - if (m_commandFifo.empty() || !m_responseFifo[1].empty()) return; + if (m_commandFifo.empty()) return; auto command = m_commandFifo.value; + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (!m_responseFifo[1].empty()) { + if (debug) { + std::string_view cmdName; + if (command > c_cdCmdEnumCount) { + cmdName = "Unknown"; + } else { + cmdName = magic_enum::enum_names()[command]; + } + PCSX::g_system->log(PCSX::LogClass::CDROM, + "CD-Rom: command %s (%i) pending, but response fifo full; won't start.\n", cmdName, + command); + } + return; + } + // unsure here... it may be per-command. + if ((m_status == Status::Seeking) && !m_responseFifo[0].valueRead) { + if (debug) { + std::string_view cmdName; + if (command > c_cdCmdEnumCount) { + cmdName = "Unknown"; + } else { + cmdName = magic_enum::enum_names()[command]; + } + PCSX::g_system->log( + PCSX::LogClass::CDROM, + "CD-Rom: command %s (%i) pending, but state machine busy, and reponse fifo full; won't start.\n", + cmdName, command); + } + return; + } + if (debug) { + std::string_view cmdName; + if (command > c_cdCmdEnumCount) { + cmdName = "Unknown"; + } else { + cmdName = magic_enum::enum_names()[command]; + } + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Starting command %s (%i)\n", cmdName, command); + } static constexpr unsigned c_commandMax = sizeof(c_commandsArgumentsCount) / sizeof(c_commandsArgumentsCount[0]); if (command >= c_commandMax) { maybeEnqueueError(1, 0x40); @@ -529,7 +617,17 @@ class CDRomImpl final : public PCSX::CDRom { } void maybeScheduleNextCommand() { - if (!responseFifoFull()) scheduleFifo(797us); + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (!responseFifoFull()) { + if (debug) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Scheduling queued next command to run.\n"); + } + scheduleFifo(797us); + } else if (debug) { + PCSX::g_system->log(PCSX::LogClass::CDROM, + "CD-Rom: Won't schedule next command to run as response fifo is full.\n"); + } } enum class SeekType { DATA, CDDA }; @@ -584,17 +682,12 @@ class CDRomImpl final : public PCSX::CDRom { // Command 6. bool cdlReadN(const QueueElement &command, bool start) { - auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); - if (m_speedChanged) { - m_speedChanged = false; - seekDelay += 650ms; - } - scheduleRead(seekDelay + computeReadDelay()); - QueueElement response; - response.pushPayloadData(getStatus()); - m_currentPosition = m_seekPosition; m_startReading = true; + m_status = Status::Idle; + scheduleRead(20ms); m_readingType = ReadingType::Normal; + QueueElement response; + response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); maybeScheduleNextCommand(); return false; diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 576975a21..ec3915de0 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -158,7 +158,8 @@ class CDRom { uint8_t payloadIndex = 0; bool isPayloadEmpty() const { return payloadSize == payloadIndex; } bool isPayloadFull() const { return payloadSize == sizeof(payload); } - bool empty() const { return (!hasValue || valueRead) && isPayloadEmpty(); } + bool empty() const { return valueEmpty() && isPayloadEmpty(); } + bool valueEmpty() const { return !hasValue || valueRead; } void clear() { hasValue = false; valueRead = false; @@ -191,15 +192,6 @@ class CDRom { QueueElement m_commandExecuting; QueueElement m_responseFifo[2]; bool responseFifoFull() { return !m_responseFifo[0].empty() && !m_responseFifo[1].empty(); } - bool maybeEnqueueResponse(QueueElement& response) { - if (m_responseFifo[0].empty()) { - m_responseFifo[0] = response; - return true; - } else if (m_responseFifo[1].empty()) { - m_responseFifo[1] = response; - } - return false; - } private: friend class Widgets::IsoBrowser; From 2532801e97d2940a40fc1544414f80d93939c12c Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 8 Mar 2023 18:26:16 -0800 Subject: [PATCH 156/185] So fucking close. --- src/core/cdrom.cc | 53 ++++++++++++++++++----------------------------- src/core/cdrom.h | 6 +++++- 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 41f4cba71..a226ff9e9 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -110,6 +110,7 @@ class CDRomImpl final : public PCSX::CDRom { m_commandExecuting.clear(); m_responseFifo[0].clear(); m_responseFifo[1].clear(); + m_readingState = ReadingState::None; } void fifoScheduledCallback() override { @@ -137,22 +138,20 @@ class CDRomImpl final : public PCSX::CDRom { static const std::chrono::nanoseconds c_retryDelay = 50us; const bool debug = PCSX::g_emulator->settings.get() .get(); - if (m_startReading) { - if (m_status == Status::Idle) { - m_status = Status::Seeking; - auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); - m_status = Status::Seeking; - if (m_speedChanged) { - m_speedChanged = false; - seekDelay += 650ms; - } - m_currentPosition = m_seekPosition; - scheduleRead(seekDelay + computeReadDelay()); - return; - } else { - m_startReading = false; - m_status = Status::ReadingData; + if (m_readingState == ReadingState::Seeking) { + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + m_status = Status::Seeking; + if (m_speedChanged) { + m_speedChanged = false; + seekDelay += 650ms; } + m_currentPosition = m_seekPosition; + scheduleRead(seekDelay + computeReadDelay()); + m_readingState = ReadingState::Reading; + return; + } else if (m_readingState == ReadingState::Reading) { + m_readingState = ReadingState::None; + m_status = Status::ReadingData; } else if ((m_status == Status::Idle) || (m_status == Status::Seeking)) { m_readingType = ReadingType::None; if (debug) { @@ -553,7 +552,7 @@ class CDRomImpl final : public PCSX::CDRom { auto command = m_commandFifo.value; const bool debug = PCSX::g_emulator->settings.get() .get(); - if (!m_responseFifo[1].empty()) { + if (!m_responseFifo[0].valueRead || !m_responseFifo[1].empty()) { if (debug) { std::string_view cmdName; if (command > c_cdCmdEnumCount) { @@ -567,22 +566,6 @@ class CDRomImpl final : public PCSX::CDRom { } return; } - // unsure here... it may be per-command. - if ((m_status == Status::Seeking) && !m_responseFifo[0].valueRead) { - if (debug) { - std::string_view cmdName; - if (command > c_cdCmdEnumCount) { - cmdName = "Unknown"; - } else { - cmdName = magic_enum::enum_names()[command]; - } - PCSX::g_system->log( - PCSX::LogClass::CDROM, - "CD-Rom: command %s (%i) pending, but state machine busy, and reponse fifo full; won't start.\n", - cmdName, command); - } - return; - } if (debug) { std::string_view cmdName; if (command > c_cdCmdEnumCount) { @@ -682,7 +665,6 @@ class CDRomImpl final : public PCSX::CDRom { // Command 6. bool cdlReadN(const QueueElement &command, bool start) { - m_startReading = true; m_status = Status::Idle; scheduleRead(20ms); m_readingType = ReadingType::Normal; @@ -690,6 +672,7 @@ class CDRomImpl final : public PCSX::CDRom { response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); maybeScheduleNextCommand(); + m_readingState = ReadingState::Seeking; return false; } @@ -735,7 +718,9 @@ class CDRomImpl final : public PCSX::CDRom { m_speed = Speed::Simple; m_status = Status::Idle; m_causeMask = 0x1f; + m_readingState = ReadingState::None; memset(m_lastLocP, 0, sizeof(m_lastLocP)); + // Probably need to cancel other scheduled tasks here. return true; } else { QueueElement response; @@ -874,6 +859,7 @@ class CDRomImpl final : public PCSX::CDRom { // Command 21. bool cdlSeekL(const QueueElement &command, bool start) { + m_readingState = ReadingState::None; if (start) { QueueElement response; response.pushPayloadData(getStatus()); @@ -910,6 +896,7 @@ class CDRomImpl final : public PCSX::CDRom { // Command 22. bool cdlSeekP(const QueueElement &command, bool start) { + m_readingState = ReadingState::None; if (start) { QueueElement response; response.pushPayloadData(getStatus()); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index ec3915de0..00e38eea3 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -118,7 +118,11 @@ class CDRom { bool m_dataRequested = false; bool m_subheaderFilter = false; bool m_realtime = false; - bool m_startReading = false; + enum class ReadingState : uint8_t { + None, + Seeking, + Reading, + } m_readingState = ReadingState::None; bool m_startPlaying = false; enum class ReadingType : uint8_t { None, From 9c1818f2f52f06617856fa4c182d077b5cc80ec7 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 8 Mar 2023 18:47:28 -0800 Subject: [PATCH 157/185] Fixing test that shouldn't pause before sending NOP command. --- src/mips/tests/cdrom/reading.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index 33e4abe13..f73d0cdad 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -597,7 +597,6 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, uint8_t response[16]; readResponse(response); - initializeTime(); CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; @@ -660,7 +659,7 @@ CESTER_TEST(simpleReadingNopQuery, test_instances, cester_assert_uint_eq(0x18, ctrl6); cester_assert_uint_eq(0x38, ctrl7); cester_assert_uint_eq(0x18, ctrl8); - cester_assert_uint_eq(0x42, response1[0]); + cester_assert_uint_eq(0x02, response1[0]); cester_assert_uint_eq(1, responseSize1); cester_assert_uint_eq(0x22, response2[0]); cester_assert_uint_eq(1, responseSize2); From 1a797b5db5c2fe7db95a55aaa4321692947e0805 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 8 Mar 2023 19:55:30 -0800 Subject: [PATCH 158/185] Being more lenient with this test. --- src/mips/tests/cdrom/reading.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/mips/tests/cdrom/reading.c b/src/mips/tests/cdrom/reading.c index f73d0cdad..63eee8056 100644 --- a/src/mips/tests/cdrom/reading.c +++ b/src/mips/tests/cdrom/reading.c @@ -698,17 +698,23 @@ CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, initializeTime(); - for (unsigned i = 0; i < 100; i++) { + unsigned countToRead = 0; + unsigned gotInt1 = 0; + + do { CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; - uint8_t cause; + uint8_t cause = 0; do { waitCDRomIRQ(); cause = ackCDRomCause(); - uint8_t response[16]; readResponse(response); + if (cause == 1) { + gotInt1 = 1; + } } while (cause == 1); - } + countToRead++; + } while (!gotInt1); CDROM_REG0 = 0; CDROM_REG1 = CDL_NOP; @@ -756,6 +762,7 @@ CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, CDROM_REG0 = 1; uint8_t cause4b = CDROM_REG3_UC; + cester_assert_uint_lt(countToRead, 80); cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(1, cause2); @@ -778,9 +785,9 @@ CESTER_TEST(simpleReadingNopSeriesQuery, test_instances, cester_assert_uint_eq(1, responseSize2); cester_assert_uint_eq(0x22, response3[0]); cester_assert_uint_eq(1, responseSize3); - cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(0x02, response4[0]); cester_assert_uint_eq(1, responseSize4); - ramsyscall_printf("Long read, nop series then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", time1, time2, time3, time4); + ramsyscall_printf("Long read, nop series of %i then pause, ack in %ius, ready in %ius, ack in %ius, complete in %ius\n", countToRead, time1, time2, time3, time4); ) CESTER_TEST(simpleReadingNoSeekNopQueries, test_instances, From 47634e2fcf5beee0590200a62a7b9036eaee886e Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 8 Mar 2023 20:10:49 -0800 Subject: [PATCH 159/185] All tests passing. --- src/core/cdrom.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index a226ff9e9..640328039 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -139,7 +139,7 @@ class CDRomImpl final : public PCSX::CDRom { const bool debug = PCSX::g_emulator->settings.get() .get(); if (m_readingState == ReadingState::Seeking) { - auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA); + auto seekDelay = computeSeekDelay(m_currentPosition, m_seekPosition, SeekType::DATA, true); m_status = Status::Seeking; if (m_speedChanged) { m_speedChanged = false; @@ -615,7 +615,7 @@ class CDRomImpl final : public PCSX::CDRom { enum class SeekType { DATA, CDDA }; - std::chrono::nanoseconds computeSeekDelay(MSF from, MSF to, SeekType seekType) { + std::chrono::nanoseconds computeSeekDelay(MSF from, MSF to, SeekType seekType, bool forReading = false) { unsigned destTrack = m_iso->getTrack(to); if (destTrack == 0) return 650ms; if ((seekType == SeekType::DATA) && (m_iso->getTrackType(destTrack) == PCSX::CDRIso::TrackType::CDDA)) { @@ -629,7 +629,7 @@ class CDRomImpl final : public PCSX::CDRom { } // TODO: ought to be a decent approximation for now, // but may require some tuning later on. - return std::chrono::microseconds(distance * 3) + 167ms; + return std::chrono::microseconds(distance * 3) + (forReading ? 1ms : 167ms); } std::chrono::nanoseconds computeReadDelay() { return m_speed == Speed::Simple ? 13333us : 6666us; } From 2e54913ac0aad643abd0c34e6763b80a45860a01 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 13 Mar 2023 18:08:59 -0700 Subject: [PATCH 160/185] Better logs. --- src/core/cdrom.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 640328039..ca030e27e 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -261,7 +261,7 @@ class CDRomImpl final : public PCSX::CDRom { actuallyTriggering = true; } const bool debug = PCSX::g_emulator->settings.get() - .get(); + .get(); if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; if (actuallyTriggering) { @@ -533,6 +533,13 @@ class CDRomImpl final : public PCSX::CDRom { .get()) { PCSX::g_emulator->m_debug->checkDMAwrite(3, madr, size); } + const bool debug = PCSX::g_emulator->settings.get() + .get(); + if (debug) { + auto ®s = PCSX::g_emulator->m_cpu->m_regs; + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] DMA transfer requested to address %08x, size %08x\n", + regs.pc, regs.cycle, madr, size); + } if (chcr == 0x11400100) { scheduleDMA(size / 16); } else { @@ -781,14 +788,14 @@ class CDRomImpl final : public PCSX::CDRom { m_readSpan = ReadSpan::S2340; break; case 3: - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode:\n", mode); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode: %02x\n", mode); PCSX::g_system->pause(); break; } m_subheaderFilter = (mode & 0x08) != 0; m_realtime = (mode & 0x40) != 0; if (mode & 0x07) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode:\n", mode); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: unsupported mode: %02x\n", mode); PCSX::g_system->pause(); } QueueElement response; From 682d7b32f1d469d7b4cb8e0038463f6e8a3432a8 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 17 Mar 2023 23:44:10 -0700 Subject: [PATCH 161/185] Adding subheaders decoder. --- src/cdrom/iec-60908b.h | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/cdrom/iec-60908b.h b/src/cdrom/iec-60908b.h index a29d764ce..2ce5f8519 100644 --- a/src/cdrom/iec-60908b.h +++ b/src/cdrom/iec-60908b.h @@ -184,6 +184,53 @@ void computeEDCECC(uint8_t *sector); // Compute the CRC-16 for the SubQ channel. uint16_t subqCRC(const uint8_t *d, int len = 10); +struct SubHeaders { + uint8_t fileNumber; + uint8_t channelNumber; + uint8_t subMode; + uint8_t codingInfo; + bool fromBuffer(const uint8_t buffer[]) { + fileNumber = buffer[0]; + channelNumber = buffer[1]; + subMode = buffer[2]; + codingInfo = buffer[3]; + return (buffer[0] == buffer[4]) && (buffer[1] == buffer[5]) && (buffer[2] == buffer[6]) && + (buffer[3] == buffer[7]); + } + void toBuffer(uint8_t buffer[]) const { + buffer[0] = buffer[4] = fileNumber; + buffer[1] = buffer[5] = channelNumber; + buffer[2] = buffer[6] = subMode; + buffer[3] = buffer[7] = codingInfo; + } + bool isEndOfRecord() const { return subMode & 0x01; } + bool isVideo() const { return subMode & 0x02; } + bool isAudio() const { return subMode & 0x04; } + bool isData() const { return subMode & 0x08; } + bool isTrigger() const { return subMode & 0x10; } + bool isForm2() const { return subMode & 0x20; } + bool isRealTime() const { return subMode & 0x40; } + bool isEOF() const { return subMode & 0x80; } + + void setEndOfRecord() { subMode |= 0x01; } + void setVideo() { subMode |= 0x02; } + void setAudio() { subMode |= 0x04; } + void setData() { subMode |= 0x08; } + void setTrigger() { subMode |= 0x10; } + void setForm2() { subMode |= 0x20; } + void setRealTime() { subMode |= 0x40; } + void setEOF() { subMode |= 0x80; } + + void clearEndOfRecord() { subMode &= ~0x01; } + void clearVideo() { subMode &= ~0x02; } + void clearAudio() { subMode &= ~0x04; } + void clearData() { subMode &= ~0x08; } + void clearTrigger() { subMode &= ~0x10; } + void clearForm2() { subMode &= ~0x20; } + void clearRealTime() { subMode &= ~0x40; } + void clearEOF() { subMode &= ~0x80; } +}; + } // namespace IEC60908b } // namespace PCSX From 87d0ed4d4f9486c93f0b4bc567beb67f110ce090 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 17 Mar 2023 23:44:54 -0700 Subject: [PATCH 162/185] Better log lines. --- src/core/cdrom.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index ca030e27e..b47bfb670 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -122,7 +122,7 @@ class CDRomImpl final : public PCSX::CDRom { psxHu32ref(0x1070) |= SWAP_LE32(uint32_t(4)); if (debug) { PCSX::g_system->log(PCSX::LogClass::CDROM, - "CDRom: response fifo sliding one response, triggering IRQ.\n"); + "CD-Rom: response fifo sliding one response, triggering IRQ.\n"); } } maybeStartCommand(); @@ -155,7 +155,7 @@ class CDRomImpl final : public PCSX::CDRom { } else if ((m_status == Status::Idle) || (m_status == Status::Seeking)) { m_readingType = ReadingType::None; if (debug) { - PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: cancelling read.\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: readInterrupt: cancelling read.\n"); } return; } @@ -600,6 +600,9 @@ class CDRomImpl final : public PCSX::CDRom { if (handler) { if ((this->*handler)(m_commandFifo, true)) m_commandExecuting = m_commandFifo; } else { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unsupported command %i (%s).\n", command, + magic_enum::enum_names()[command]); + PCSX::g_system->pause(); maybeEnqueueError(1, 0x40); maybeScheduleNextCommand(); } @@ -742,7 +745,7 @@ class CDRomImpl final : public PCSX::CDRom { bool cdlMute(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? - PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: Mute - not yet implemented.\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Mute - not yet implemented.\n"); QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); @@ -754,7 +757,7 @@ class CDRomImpl final : public PCSX::CDRom { bool cdlDemute(const QueueElement &command, bool start) { // TODO: probably should error out if no disc or // lid open? - PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: Demute - not yet implemented.\n"); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Demute - not yet implemented.\n"); QueueElement response; response.pushPayloadData(getStatus()); maybeTriggerIRQ(Cause::Acknowledge, response); @@ -1114,7 +1117,7 @@ void PCSX::CDRom::parseIso() { std::string lineStorage = systemcnf->gets(); auto line = StringsHelpers::trim(lineStorage); if (!StringsHelpers::startsWith(line, "BOOT")) continue; - auto pathLoc = line.find("cdrom:"); + auto pathLoc = line.find("CD-Rom:"); if (pathLoc == std::string::npos) break; auto paths = StringsHelpers::split(line.substr(pathLoc + 6), "/\\"); if (paths.empty()) break; From 01671b714f174c2908f2776bec1ebc82f85aba24 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 17 Mar 2023 23:45:21 -0700 Subject: [PATCH 163/185] Typo. --- src/core/cdrom.cc | 2 +- src/core/cdrom.h | 2 +- src/core/r3000a.cc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index b47bfb670..088a2b198 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -216,7 +216,7 @@ class CDRomImpl final : public PCSX::CDRom { } } - void scheduleDmaCallback() override { + void scheduledDmaCallback() override { if (HW_DMA3_CHCR & SWAP_LE32(0x01000000)) { HW_DMA3_CHCR &= SWAP_LE32(~0x01000000); DMA_INTERRUPT<3>(); diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 00e38eea3..f7aab26cd 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -82,7 +82,7 @@ class CDRom { virtual void fifoScheduledCallback() = 0; virtual void commandsScheduledCallback() = 0; virtual void readScheduledCallback() = 0; - virtual void scheduleDmaCallback() = 0; + virtual void scheduledDmaCallback() = 0; virtual uint8_t read0() = 0; virtual uint8_t read1() = 0; virtual uint8_t read2() = 0; diff --git a/src/core/r3000a.cc b/src/core/r3000a.cc index 7712724f8..692ef1e39 100644 --- a/src/core/r3000a.cc +++ b/src/core/r3000a.cc @@ -320,7 +320,7 @@ void PCSX::R3000Acpu::branchTest() { checkAndUpdate(Schedule::SPUDMA, spuInterrupt); checkAndUpdate(Schedule::MDECINDMA, g_emulator->m_mdec->scheduledCallback0); checkAndUpdate(Schedule::GPUOTCDMA, gpuotcInterrupt); - checkAndUpdate(Schedule::CDRDMA, g_emulator->m_cdrom->scheduleDmaCallback); + checkAndUpdate(Schedule::CDRDMA, g_emulator->m_cdrom->scheduledDmaCallback); m_regs.lowestTarget = lowestTarget; } if ((psxHu32(0x1070) & psxHu32(0x1074)) && ((m_regs.CP0.n.Status & 0x401) == 0x401)) { From a779b004ae076cf61e8eb40cca1b6703417a44c1 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 17 Mar 2023 23:45:46 -0700 Subject: [PATCH 164/185] Skipping over XA sectors for now. --- src/core/cdrom.cc | 57 ++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 088a2b198..6dd649d2f 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -175,23 +175,38 @@ class CDRomImpl final : public PCSX::CDRom { auto buffer = m_iso->getBuffer(); memcpy(m_lastLocL, buffer, sizeof(m_lastLocL)); uint32_t size = 0; - switch (m_readSpan) { - case ReadSpan::S2048: - size = 2048; - if (buffer[3] == 1) { - memcpy(m_dataFIFO, buffer + 4, 2048); - } else { - memcpy(m_dataFIFO, buffer + 12, 2048); + bool passToData = true; + if ((buffer[3] == 2) && m_realtime) { + PCSX::IEC60908b::SubHeaders subHeaders; + subHeaders.fromBuffer(buffer + 4); + if (subHeaders.isRealTime() && subHeaders.isAudio()) { + passToData = false; + if (m_subheaderFilter) { + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: filtering not supported yet.\n"); + PCSX::g_system->pause(); } - break; - case ReadSpan::S2328: - size = 2328; - memcpy(m_dataFIFO, buffer + 12, 2328); - break; - case ReadSpan::S2340: - size = 2340; - memcpy(m_dataFIFO, buffer, 2340); - break; + // TODO: play XA sector. + } + } + if (passToData) { + switch (m_readSpan) { + case ReadSpan::S2048: + size = 2048; + if (buffer[3] == 1) { + memcpy(m_dataFIFO, buffer + 4, 2048); + } else { + memcpy(m_dataFIFO, buffer + 12, 2048); + } + break; + case ReadSpan::S2328: + size = 2328; + memcpy(m_dataFIFO, buffer + 12, 2328); + break; + case ReadSpan::S2340: + size = 2340; + memcpy(m_dataFIFO, buffer, 2340); + break; + } } auto readDelay = computeReadDelay(); m_dataFIFOIndex = 0; @@ -200,12 +215,14 @@ class CDRomImpl final : public PCSX::CDRom { m_currentPosition++; if (debug) { std::string msfFormat = fmt::format("{}", m_currentPosition); - PCSX::g_system->log(PCSX::LogClass::CDROM, "CDRom: readInterrupt: advancing to %s.\n", + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: readInterrupt: advancing to %s.\n", msfFormat); } - QueueElement ready; - ready.pushPayloadData(getStatus()); - maybeTriggerIRQ(Cause::DataReady, ready); + if (passToData) { + QueueElement ready; + ready.pushPayloadData(getStatus()); + maybeTriggerIRQ(Cause::DataReady, ready); + } scheduleRead(readDelay); } } break; From 7becd07dab4b234d1200492daf1aa954192fe23b Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Fri, 17 Mar 2023 23:46:02 -0700 Subject: [PATCH 165/185] Bandaid for bad DMA computation. --- src/core/cdrom.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 6dd649d2f..7f4972b83 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -536,8 +536,7 @@ class CDRomImpl final : public PCSX::CDRom { } void dma(uint32_t madr, uint32_t bcr, uint32_t chcr) override { - uint32_t size = bcr >> 16; - size *= bcr & 0xffff; + uint32_t size = bcr & 0xffff; size *= 4; if (size == 0) size = 0xffffffff; size = std::min(m_dataFIFOSize - m_dataFIFOIndex, size); From f70eca64e40e8b3b4784a702ae48baee948c23c5 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sat, 18 Mar 2023 01:25:23 -0700 Subject: [PATCH 166/185] Derp. --- src/core/cdrom.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 7f4972b83..47f1471c0 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -1133,7 +1133,7 @@ void PCSX::CDRom::parseIso() { std::string lineStorage = systemcnf->gets(); auto line = StringsHelpers::trim(lineStorage); if (!StringsHelpers::startsWith(line, "BOOT")) continue; - auto pathLoc = line.find("CD-Rom:"); + auto pathLoc = line.find("cdrom:"); if (pathLoc == std::string::npos) break; auto paths = StringsHelpers::split(line.substr(pathLoc + 6), "/\\"); if (paths.empty()) break; From 2f882a4d0bc8a83f13077f24538db6ab05c8247e Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Tue, 18 Apr 2023 21:49:29 -0700 Subject: [PATCH 167/185] Factorizing logging. --- src/core/cdrom.cc | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index d63d142a6..b8d325bf0 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -73,6 +73,14 @@ class CDRomImpl final : public PCSX::CDRom { CdlReadToc = 30, }; + std::string_view commandName(uint8_t command) { + if (command > c_cdCmdEnumCount) { + return "Unknown"; + } else { + return magic_enum::enum_names()[command]; + } + } + static constexpr size_t c_cdCmdEnumCount = magic_enum::enum_count(); static constexpr bool isValidBCD(uint8_t value) { return (value & 0x0f) <= 9 && (value & 0xf0) <= 0x90; } static std::optional getMSF(const uint8_t *msf) { @@ -579,26 +587,15 @@ class CDRomImpl final : public PCSX::CDRom { .get(); if (!m_responseFifo[0].valueRead || !m_responseFifo[1].empty()) { if (debug) { - std::string_view cmdName; - if (command > c_cdCmdEnumCount) { - cmdName = "Unknown"; - } else { - cmdName = magic_enum::enum_names()[command]; - } PCSX::g_system->log(PCSX::LogClass::CDROM, - "CD-Rom: command %s (%i) pending, but response fifo full; won't start.\n", cmdName, - command); + "CD-Rom: command %s (%i) pending, but response fifo full; won't start.\n", + commandName(command), command); } return; } if (debug) { - std::string_view cmdName; - if (command > c_cdCmdEnumCount) { - cmdName = "Unknown"; - } else { - cmdName = magic_enum::enum_names()[command]; - } - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Starting command %s (%i)\n", cmdName, command); + PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Starting command %s (%i)\n", commandName(command), + command); } static constexpr unsigned c_commandMax = sizeof(c_commandsArgumentsCount) / sizeof(c_commandsArgumentsCount[0]); if (command >= c_commandMax) { @@ -619,7 +616,7 @@ class CDRomImpl final : public PCSX::CDRom { if ((this->*handler)(m_commandFifo, true)) m_commandExecuting = m_commandFifo; } else { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: Unsupported command %i (%s).\n", command, - magic_enum::enum_names()[command]); + commandName(command)); PCSX::g_system->pause(); maybeEnqueueError(1, 0x40); maybeScheduleNextCommand(); @@ -1110,7 +1107,7 @@ class CDRomImpl final : public PCSX::CDRom { regs.pc, regs.cycle, command.value); } else { PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] Command: %s\n", regs.pc, regs.cycle, - magic_enum::enum_names()[command.value]); + commandName(command.value)); } break; } From 0e6a22342df91d51a893b4ff36425a078affd21c Mon Sep 17 00:00:00 2001 From: Caleb Yates Date: Sun, 25 Jun 2023 22:00:20 -0500 Subject: [PATCH 168/185] Fixing cdlsetmode test message --- src/mips/tests/cdrom/cdlsetmode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/cdlsetmode.c b/src/mips/tests/cdrom/cdlsetmode.c index 90406a0ab..399c7b042 100644 --- a/src/mips/tests/cdrom/cdlsetmode.c +++ b/src/mips/tests/cdrom/cdlsetmode.c @@ -129,5 +129,5 @@ CESTER_TEST(cdlSetModeWithTooManyArgs, test_instance, // Typical value seems to be around 750us. cester_assert_uint_ge(errorTime, 500); cester_assert_uint_lt(errorTime, 7000); - ramsyscall_printf("No args setMode: errored in %ius\n", errorTime); + ramsyscall_printf("Too many args setMode: errored in %ius\n", errorTime); ) From a7e54f3a063fa2df73d0448d355d9654d90bb31b Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 18 Dec 2023 07:49:30 -0800 Subject: [PATCH 169/185] Fixing merge failure. --- src/core/cdrom.cc | 2 +- src/core/luaiso.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index b8d325bf0..f56a6226d 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -25,7 +25,6 @@ #include -#include "cdrom/iec-60908b.h" #include "cdrom/iso9660-reader.h" #include "core/debug.h" #include "core/psxdma.h" @@ -33,6 +32,7 @@ #include "magic_enum/include/magic_enum.hpp" #include "spu/interface.h" #include "support/strings-helpers.h" +#include "supportpsx/iec-60908b.h" namespace { diff --git a/src/core/luaiso.cc b/src/core/luaiso.cc index 3c0266ded..0a8c4fca0 100644 --- a/src/core/luaiso.cc +++ b/src/core/luaiso.cc @@ -23,12 +23,12 @@ #include "cdrom/cdriso.h" #include "cdrom/file.h" -#include "cdrom/iec-60908b.h" #include "cdrom/iso9660-builder.h" #include "cdrom/iso9660-reader.h" #include "core/cdrom.h" #include "lua/luafile.h" #include "lua/luawrapper.h" +#include "supportpsx/iec-60908b.h" namespace { From 68192a210f0c4ecbb8e8256cd482efba217c7a62 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 7 Feb 2024 22:23:24 -0800 Subject: [PATCH 170/185] Adjusting readme from latest CLI flags. --- src/mips/tests/cdrom/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index d85e019ec..f5618427d 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -5,7 +5,7 @@ This directory contains tests for the CDRom controller of the PS1. They are assu The script can be run using the following command: ```bash -pcsx-redux -stdout -lua_stdout -testmode -no-gui-logs -iso UNIROM_BOOTDISC.bin -exec "dofile 'create-test-iso.lua'" +pcsx-redux -cli -iso UNIROM_BOOTDISC.bin -exec "dofile 'create-test-iso.lua'" ``` This will emit a `test.cue` file, and multiple corresponding tracks. The data track will contain Unirom itself, for potentially booting on a retail machine and be able to upload the tests to the machine using [`nops`](https://github.com/JonathanDotCel/NOTPSXSerial). From c64112886f4334266b62bf09c07c954586aed861 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Wed, 7 Feb 2024 22:24:06 -0800 Subject: [PATCH 171/185] Adding CXD1199 datasheet information. --- src/core/cdrom.cc | 225 ++++++++++++++++++++++++++++++++++++---------- src/core/cdrom.h | 6 +- 2 files changed, 181 insertions(+), 50 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index f56a6226d..8ebc16935 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -38,6 +38,9 @@ namespace { using namespace std::literals; +// The buffer/decoder chip the PSX CPU will talk to is the CXD1199, which +// datasheet can be found at https://archive.org/details/cxd-1199 + class CDRomImpl final : public PCSX::CDRom { enum Commands { CdlSync = 0, @@ -104,14 +107,14 @@ class CDRomImpl final : public PCSX::CDRom { m_seed = 9223521712174600777ull; m_dataFIFOIndex = 0; m_dataFIFOSize = 0; - m_registerIndex = 0; + m_registerAddress = 0; m_currentPosition.reset(); m_seekPosition.reset(); m_speed = Speed::Simple; m_speedChanged = false; m_status = Status::Idle; m_dataRequested = false; - m_causeMask = 0x1f; + m_interruptCauseMask = 0x1f; m_subheaderFilter = false; m_realtime = false; m_commandFifo.clear(); @@ -279,7 +282,7 @@ class CDRomImpl final : public PCSX::CDRom { void maybeTriggerIRQ(Cause cause, QueueElement &element) { uint8_t causeValue = static_cast(cause); uint8_t bit = 1 << (causeValue - 1); - if (m_causeMask & bit) { + if (m_interruptCauseMask & bit) { element.setValue(cause); bool actuallyTriggering = false; if (maybeEnqueueResponse(element)) { @@ -329,15 +332,49 @@ class CDRomImpl final : public PCSX::CDRom { } uint8_t read0() override { - uint8_t v01 = m_registerIndex & 3; - uint8_t adpcmPlaying = 0; - uint8_t v3 = m_commandFifo.isPayloadEmpty() ? 0x08 : 0; - uint8_t v4 = !m_commandFifo.isPayloadFull() ? 0x10 : 0; - uint8_t v5 = !m_responseFifo[0].isPayloadEmpty() ? 0x20 : 0; - uint8_t v6 = m_dataFIFOSize != m_dataFIFOIndex ? 0x40 : 0; + // HSTS (host status) register + /* + bit 7: BUSYSTS (busy status) + This is high when the host writes a command into the command register and low when the sub + CPU sets the CLRBUSY bit (bit 6) of the CLRCTL register. + */ uint8_t v7 = m_commandFifo.hasValue ? 0x80 : 0; - - uint8_t ret = v01 | adpcmPlaying | v3 | v4 | v5 | v6 | v7; + /* + bit 6: DRQSTS (data request status) + Indicates to the host that the buffer memory data transfer request status is established. When + transferring data in the I/O mode, the host should confirm that this bit is high before accessing the + WRDATA or RDDATA register. + */ + uint8_t v6 = m_dataFIFOSize != m_dataFIFOIndex ? 0x40 : 0; + /* + bit 5: RSLRRDY (result read ready) + The result register is not empty when this bit is high. At this time, the host can read the result + register. + */ + uint8_t v5 = !m_responseFifo[0].isPayloadEmpty() ? 0x20 : 0; + /* + bit 4: PRMWRDY (parameter write ready) + The PARAMETER register is not full when this bit is high. At this time, the host writes data into the + PARAMETER register. + */ + uint8_t v4 = !m_commandFifo.isPayloadFull() ? 0x10 : 0; + /* + bit 3: PRMEMPT (parameter empty) + The PARAMETER register is empty when this bit is high. + */ + uint8_t v3 = m_commandFifo.isPayloadEmpty() ? 0x08 : 0; + /* + bit 2: ADPBUSY (ADPCM busy) + This bit is set high for ADPCM decoding. + */ + uint8_t v2 = 0; /* adpcmPlaying */ + /* + bits 1, 0: RA1, 0 + The values of the RA1 and 0 bits for the ADDRESS register can be read from these bits. + */ + uint8_t v01 = m_registerAddress & 3; + + uint8_t ret = v01 | v2 | v3 | v4 | v5 | v6 | v7; const bool debug = PCSX::g_emulator->settings.get() .get(); if (debug) { @@ -349,6 +386,7 @@ class CDRomImpl final : public PCSX::CDRom { } uint8_t read1() override { + // RESULT uint8_t ret = m_responseFifo[0].readPayloadByte(); maybeScheduleNextCommand(); @@ -362,6 +400,7 @@ class CDRomImpl final : public PCSX::CDRom { } uint8_t read2() override { + // RD DATA uint8_t ret = 0; if (!dataFIFOHasData()) { ret = 0; @@ -379,15 +418,32 @@ class CDRomImpl final : public PCSX::CDRom { } uint8_t read3() override { + /* + * bit 4: BFWRDY (buffer write ready) + * The BFWRDY status is established if there is area where writing is possible in the buffer of 1 sector + * or more for sound map playback. It is established in any of the following cases: + * (1) When the host has set the SMEN bit (bit 5) of the HCHPCTL register high + * (2) When there is sound map data area of 1 sector or more in the buffer memory (when the buffer + * is not full) after the sound map data equivalent to 1 sector from the host has been written into + * the buffer memory + * (3) When an area for writing the sound map data has been created in the buffer memory by the + * completion of the sound map ADPCM decoding of one sector + * bit 3: BFEMPT (buffer empty) + * The BFEMPT status is established when there is no more sector data in the buffer memory upon + * completion of the sound map ADPCM decoding of one sector for sound map playback. + * bits 2 to 0: INTSTS#2 to 0 + * The values of these bits are those of the corresponding bits for the sub CPU HIFCTL register. + */ + uint8_t ret = 0; - switch (m_registerIndex & 1) { + switch (m_registerAddress & 1) { case 0: { - ret = m_causeMask | 0xe0; + // HINT MSK (host interrupt mask) + ret = m_interruptCauseMask; } break; case 1: { - // cause - // TODO: add bit 4 - ret = m_responseFifo[0].getValue() | 0xe0; + // HINT STS (host interrupt status) + ret = m_responseFifo[0].getValue(); } break; } const bool debug = PCSX::g_emulator->settings.get() @@ -395,19 +451,20 @@ class CDRomImpl final : public PCSX::CDRom { if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] r3.%i: %02x\n", regs.pc, regs.cycle, - m_registerIndex & 1, ret); + m_registerAddress & 1, ret); } - return ret; + return ret | 0xe0; } void write0(uint8_t value) override { + // ADDRESS const bool debug = PCSX::g_emulator->settings.get() .get(); if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w0: %02x\n", regs.pc, regs.cycle, value); } - m_registerIndex = value & 3; + m_registerAddress = value & 3; } void write1(uint8_t value) override { @@ -416,10 +473,11 @@ class CDRomImpl final : public PCSX::CDRom { if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w1.%i: %02x\n", regs.pc, regs.cycle, - m_registerIndex, value); + m_registerAddress, value); } - switch (m_registerIndex) { + switch (m_registerAddress) { case 0: + // COMMAND m_commandFifo.value = value; if (!m_commandFifo.hasValue) { if (PCSX::g_emulator->settings.get() @@ -431,18 +489,35 @@ class CDRomImpl final : public PCSX::CDRom { m_commandFifo.hasValue = true; break; case 1: { - // ?? + // WR DATA PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:1 not available yet\n"); PCSX::g_system->pause(); } break; case 2: { - // ?? + /* + CI (coding information) + This sets the coding information for sound map playback. The bit allocation is the same as that for the + coding information bytes of the sub header. + bits 7, 5, 3, 1: Reserved + bit 6: EMPHASIS + High: Emphasis ON + Low : Emphasis OFF + bit 4: BITLNGTH + High: 8 bits + Low : 4 bits + bit 2: FS + High: 18.9 kHz + Low : 37.8 kHz + bit 0: S/M (stereo/mono) + High: Stereo + Low : Mono + */ PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:2 not available yet\n"); PCSX::g_system->pause(); } break; case 3: { - // Volume setting RR - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w1:3 not available yet\n"); + // ATV2 Right-to-Right + m_atv[2] = value; } break; } } @@ -453,22 +528,24 @@ class CDRomImpl final : public PCSX::CDRom { if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w2.%i: %02x\n", regs.pc, regs.cycle, - m_registerIndex, value); + m_registerAddress, value); } - switch (m_registerIndex) { + switch (m_registerAddress) { case 0: { + // PARAMETER m_commandFifo.pushPayloadData(value); } break; case 1: { - m_causeMask = value; + // HINT MSK (host interrupt mask) + m_interruptCauseMask = value; } break; case 2: { - // Volume setting LL - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:2 not available yet\n"); + // ATV0 Left-to-Left + m_atv[0] = value; } break; case 3: { - // Volume setting RL - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w2:3 not available yet\n"); + // ATV3 Right-to-Left + m_atv[3] = value; } break; } } @@ -479,26 +556,66 @@ class CDRomImpl final : public PCSX::CDRom { if (debug) { auto ®s = PCSX::g_emulator->m_cpu->m_regs; PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: %08x.%08x] w3.%i: %02x\n", regs.pc, regs.cycle, - m_registerIndex, value); + m_registerAddress, value); } - switch (m_registerIndex) { + switch (m_registerAddress) { case 0: { - // ?? - if (value == 0) { + // clang-format off + /* + HCHPCTL (host chip control) register + bit 7: BFRD (buffer read) + The transfer of (drive) data from the buffer memory to the host is started by setting this bit high. + The bit is automatically set low upon completion of the transfer. + bit 6: BFWR (buffer write) + The transfer of data from the host to the buffer memory is started by setting this bit high. The bit is + automatically set low upon completion of the transfer. + bit 5: SMEN (sound map En) + This is set high to perform sound map ADPCM playback. + */ + // clang-format on + bool bfrd = value & 0x80; + bool bfwr = value & 0x40; + bool smen = value & 0x20; + if (bfrd) { + m_dataRequested = true; + m_dataFIFOSize = m_dataFIFOPending; + } else { m_dataRequested = false; m_dataFIFOSize = 0; m_dataFIFOIndex = 0; - return; } - if (value == 0x80) { - m_dataRequested = true; - m_dataFIFOSize = m_dataFIFOPending; - return; - } - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:0(%02x) not available yet\n", value); - PCSX::g_system->pause(); + m_soundMapEnabled = smen; } break; case 1: { + // clang-format off + /* + HCLRCTL (host clear control) + When each bit of this register is set high, the chip, status, register, interrupt status and interrupt request to + the host generated by the status are cleared. + bit 7: CHPRST (chip reset) + The inside of the IC is initialized by setting this bit high. The bit is automatically set low upon + completion of the initialization of the IC. There is therefore no need for the host to reset low. When + the inside of the IC is initialized by setting bit high, the XHRS pin is set low. + bit 6: CLRPRM (clear parameter) + The parameter register is cleared by setting this bit high. The bit is automatically set low upon + completion of the clearing for the parameter register. There is therefore no need for the host to + reset low. + bit 5: SMADPCLR (sound map ADPCM clear) + This bit is set high to terminate sound map ADPCM decoding forcibly. + (1) When this bit has been set high for sound map ADPCM playback (when both SMEN and + ADPBSY (HSTS register bit 2) are high): + • ADPCM decoding during playback is suspended. (Noise may be generated). + • The sound map and buffer management circuits in the IC are cleared, making the buffer + empty. The BFEMPT interrupt status is established. + (Note) Set the SMEN bit low at the same time as this bit is set high. + (2) Setting this bit high when the sound map ADPCM playback is not being performed has no + effect whatsoever + bit 4: CLRBFWRDY (clear buffer write ready interrupt) + bit 3: CLRBFEMPT (clear buffer write empty interrupt) + bits 2 to 0: CLRINT#2 to 0 (clear interrupt #2 to 0) + bit 4 clears the corresponding interrupt status. + */ + // clang-format on bool ack = false; // cause ack if (value == 0x07) { @@ -534,11 +651,23 @@ class CDRomImpl final : public PCSX::CDRom { PCSX::g_system->pause(); } break; case 2: { - // Volume setting LR - PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:2 not available yet\n"); + // ATV1 Left-to-Right + m_atv[1] = value; } break; case 3: { - // SPU settings latch + // clang-format off + /* + ADPCTL (ADPCM control) register + bit 5: CHNGATV (change ATV register) + The host sets this bit high after the changes of the ATV 3 to 0 registers have been completed. The + attenuator value in the IC is switched for the first time. There is no need for the host to set this bit + low. The bit used to set the ATV3 to 0 registers of the host and to synchronize the IC audio + playback. + bit 0: ADPMUTE (ADPCM mute) + Set high to mute the ADPCM sound for ADPCM decoding. + bits 7, 6, 4 to 1: Reserved + */ + // clang-format on PCSX::g_system->log(PCSX::LogClass::CDROM, "CD-Rom: w3:3 not available yet\n"); } break; } @@ -742,7 +871,7 @@ class CDRomImpl final : public PCSX::CDRom { m_invalidLocL = false; m_speed = Speed::Simple; m_status = Status::Idle; - m_causeMask = 0x1f; + m_interruptCauseMask = 0x1f; m_readingState = ReadingState::None; memset(m_lastLocP, 0, sizeof(m_lastLocP)); // Probably need to cancel other scheduled tasks here. diff --git a/src/core/cdrom.h b/src/core/cdrom.h index c5a7a6fba..32ddb5a4d 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -113,7 +113,7 @@ class CDRom { uint32_t m_dataFIFOIndex = 0; uint32_t m_dataFIFOSize = 0; uint32_t m_dataFIFOPending = 0; - uint8_t m_registerIndex = 0; + uint8_t m_registerAddress = 0; bool m_motorOn = false; bool m_speedChanged = false; bool m_invalidLocL = false; @@ -139,7 +139,9 @@ class CDRom { } m_status = Status::Idle; enum class Speed : uint8_t { Simple, Double } m_speed; enum class ReadSpan : uint8_t { S2048, S2328, S2340 } m_readSpan; - uint8_t m_causeMask = 0x1f; + uint8_t m_interruptCauseMask = 0x1f; + uint8_t m_atv[4] = {0}; + bool m_soundMapEnabled = false; enum class Cause : uint8_t { None = 0, From 44c3ef549052d8812748955303b4a8fb3246f31d Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 19 Feb 2024 23:38:43 -0800 Subject: [PATCH 172/185] Even raw MODE2 should probably regenerate ECC/EDC. --- src/cdrom/iso9660-builder.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cdrom/iso9660-builder.cc b/src/cdrom/iso9660-builder.cc index da85b95ab..2a2f0252a 100644 --- a/src/cdrom/iso9660-builder.cc +++ b/src/cdrom/iso9660-builder.cc @@ -68,6 +68,7 @@ PCSX::IEC60908b::MSF PCSX::ISO9660Builder::writeSectorAt(const uint8_t* sectorDa msf.toBCD(ptr + 12); ptr[15] = 2; memcpy(ptr + 16, sectorData, 2336); + compute_edcecc(ptr); m_out->writeAt(std::move(slice), lba * IEC60908b::FRAMESIZE_RAW); break; case SectorMode::M2_FORM1: From 93a52f242dd5abd4a727fac6f2e0983715d7fb75 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 19 Feb 2024 23:39:17 -0800 Subject: [PATCH 173/185] Adding convenience `cast` method to LuaBuffer. --- src/lua/fileffimeta.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lua/fileffimeta.lua b/src/lua/fileffimeta.lua index a15046bdb..79ee646c0 100644 --- a/src/lua/fileffimeta.lua +++ b/src/lua/fileffimeta.lua @@ -55,6 +55,10 @@ local bufferMeta = { end elseif index == 'pbSlice' then return Support._internal.createPBSliceFromBuffer(buffer) + elseif index == 'cast' then + return function(buffer, ctype) + return ffi.cast(ctype, buffer.data) + end end error('Unknown index `' .. index .. '` for LuaBuffer') end, From 3ffd75a13499160a220d0d8a87b643fc60116ab9 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 19 Feb 2024 23:40:11 -0800 Subject: [PATCH 174/185] Further simplifying run command for test case generation. --- src/mips/tests/cdrom/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mips/tests/cdrom/README.md b/src/mips/tests/cdrom/README.md index f5618427d..680aac38b 100644 --- a/src/mips/tests/cdrom/README.md +++ b/src/mips/tests/cdrom/README.md @@ -5,7 +5,7 @@ This directory contains tests for the CDRom controller of the PS1. They are assu The script can be run using the following command: ```bash -pcsx-redux -cli -iso UNIROM_BOOTDISC.bin -exec "dofile 'create-test-iso.lua'" +pcsx-redux -cli -iso UNIROM_BOOTDISC.bin -dofile create-test-iso.lua ``` This will emit a `test.cue` file, and multiple corresponding tracks. The data track will contain Unirom itself, for potentially booting on a retail machine and be able to upload the tests to the machine using [`nops`](https://github.com/JonathanDotCel/NOTPSXSerial). From ed239cd520587fbf31cc14e151ad0834ae57b76c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 19 Feb 2024 23:40:40 -0800 Subject: [PATCH 175/185] Generate XA audio wave in the test iso. --- src/mips/tests/cdrom/create-test-iso.lua | 60 ++++++++++++++++++++++-- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/mips/tests/cdrom/create-test-iso.lua b/src/mips/tests/cdrom/create-test-iso.lua index 6b0f1947e..9b5864fc9 100644 --- a/src/mips/tests/cdrom/create-test-iso.lua +++ b/src/mips/tests/cdrom/create-test-iso.lua @@ -17,9 +17,11 @@ -- This script creates a test ISO image for the CDROM unit tests. +local ffi = require 'ffi' +local bit = require 'bit' local uniromDisc = PCSX.getCurrentIso() local uniromDiscReader = uniromDisc:createReader() -local uniromFile = uniromDiscReader:open('UNIROM_B.EXE;1') +local uniromFile = uniromDiscReader:open 'UNIROM_B.EXE;1' local licenseFile = uniromDisc:open(0, 2352 * 16, 'RAW') local iso = PCSX.isoBuilder(Support.File.open('test.bin', 'TRUNCATE')) iso:writeLicense(licenseFile) @@ -65,7 +67,48 @@ while not uniromFile:eof() do end ffi.fill(b.data, 2048) -for i = count, 70 * 60 * 75 - 1 do +for i = count, 30 * 60 * 75 - 1 do + b[0] = bit.band(i, 0xff) + b[1] = bit.band(bit.rshift(i, 8), 0xff) + b[2] = bit.band(bit.rshift(i, 16), 0xff) + iso:writeSector(b) +end + +local function generateToneSample(frequency, sampleRate, t) + return math.sin(2 * math.pi * frequency * t / sampleRate) +end + +local xa = Support.NewLuaBuffer(2336) +ffi.fill(xa.data, 2336) +local e = PCSX.Adpcm.NewEncoder() +e:reset 'XA' +local samples = ffi.new('int16_t[?]', 224 * 18) +for t = 0, 224 * 18 - 1 do + samples[t] = 25000 * generateToneSample(504, 37800, t) +end +for i = 0, 18 - 1 do + e:processXABlock(samples + 224 * i, xa:cast 'uint8_t *' + 8 + 128 * i, 'XAFourBits', 1) +end +xa[0] = 0x01 +xa[1] = 0x00 +xa[2] = 0x64 +xa[3] = 0x00 +xa[4] = 0x01 +xa[5] = 0x00 +xa[6] = 0x64 +xa[7] = 0x00 +for i = 30 * 60 * 75, 40 * 60 * 75 - 1 do + if i % 16 == 0 then + iso:writeSector(xa, 'M2_RAW') + else + b[0] = bit.band(i, 0xff) + b[1] = bit.band(bit.rshift(i, 8), 0xff) + b[2] = bit.band(bit.rshift(i, 16), 0xff) + iso:writeSector(b) + end +end + +for i = 40 * 60 * 75, 70 * 60 * 75 - 1 do b[0] = bit.band(i, 0xff) b[1] = bit.band(bit.rshift(i, 8), 0xff) b[2] = bit.band(bit.rshift(i, 16), 0xff) @@ -73,6 +116,13 @@ for i = count, 70 * 60 * 75 - 1 do end b:resize(2352) +for i = 0, 588 - 1 do + local s = 25000 * generateToneSample(450, 44100, i) + b[i * 4 + 0] = bit.band(s, 0xff) + b[i * 4 + 1] = bit.band(bit.rshift(s, 8), 0xff) + b[i * 4 + 2] = b[i * 4 + 0] + b[i * 4 + 3] = b[i * 4 + 1] +end local audioTrack audioTrack = Support.File.open('test-t2.bin', 'TRUNCATE') for i = 1, 75 * 5 do @@ -96,7 +146,7 @@ for i = 1, 75 * 5 + 15 do end local cue = Support.File.open('test.cue', 'TRUNCATE') -cue:write([[ +cue:write [[ FILE "test.bin" BINARY TRACK 01 MODE2/2352 INDEX 01 00:00:00 @@ -118,7 +168,7 @@ FILE "test-t6.bin" BINARY TRACK 06 AUDIO INDEX 00 00:00:00 INDEX 01 00:02:00 -]]) +]] for i = 7, 25 do audioTrack = Support.File.open(string.format('test-t%d.bin', i), 'TRUNCATE') @@ -127,7 +177,7 @@ for i = 7, 25 do end cue:write(string.format('FILE "test-t%d.bin" BINARY\n', i)) cue:write(string.format(' TRACK %02d AUDIO\n', i)) - cue:write(' INDEX 01 00:02:00\n') + cue:write ' INDEX 01 00:02:00\n' end PCSX.quit() From 6bfe4932d656a453cfc35accc77e666c6bb8a317 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 20 Feb 2024 20:06:58 -0800 Subject: [PATCH 176/185] Adding command 0 'support'. --- src/core/cdrom.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 8ebc16935..af279cf40 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -788,6 +788,13 @@ class CDRomImpl final : public PCSX::CDRom { std::chrono::nanoseconds computeReadDelay() { return m_speed == Speed::Simple ? 13333us : 6666us; } + // "Command" 0, which doesn't actually exist. + bool cdlSync(const QueueElement &command, bool start) { + maybeEnqueueError(1, 0x40); + maybeScheduleNextCommand(); + return false; + } + // Command 1. bool cdlNop(const QueueElement &command, bool start) { QueueElement response; @@ -1152,7 +1159,7 @@ class CDRomImpl final : public PCSX::CDRom { &CDRomImpl::cdlGetClock, &CDRomImpl::cdlTest, &CDRomImpl::cdlID, &CDRomImpl::cdlReadS, // 24 &CDRomImpl::cdlReset, &CDRomImpl::cdlGetQ, &CDRomImpl::cdlReadTOC, // 28 #else - nullptr, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, nullptr, // 0 + &CDRomImpl::cdlSync, &CDRomImpl::cdlNop, &CDRomImpl::cdlSetLoc, nullptr, // 0 nullptr, nullptr, &CDRomImpl::cdlReadN, nullptr, // 4 nullptr, &CDRomImpl::cdlPause, &CDRomImpl::cdlInit, &CDRomImpl::cdlMute, // 8 &CDRomImpl::cdlDemute, nullptr, &CDRomImpl::cdlSetMode, nullptr, // 12 From f1f438159ca629af0efc55f35492a0af6766d5ab Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 3 Mar 2024 20:31:28 -0800 Subject: [PATCH 177/185] Adding test for over-reading of response buffers. --- src/mips/tests/cdrom/cdlid.c | 96 ++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/src/mips/tests/cdrom/cdlid.c b/src/mips/tests/cdrom/cdlid.c index 0598defbe..791ec677a 100644 --- a/src/mips/tests/cdrom/cdlid.c +++ b/src/mips/tests/cdrom/cdlid.c @@ -112,3 +112,99 @@ CESTER_TEST(cdlIdTooManyArgs, test_instance, ramsyscall_printf("Basic cdlId with too many args, errored in %ius\n", errorTime); ) +CESTER_TEST(cdlIdReadsTooMuchThencdlGetTN, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETID; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[32]; + for (unsigned i = 0; i < 32; i++) { + response2[i] = CDROM_REG1; + } + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETTN; + + waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t response3[32]; + for (unsigned i = 0; i < 32; i++) { + response3[i] = CDROM_REG1; + } + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x38, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + for (unsigned i = 0; i < 16; i++) { + cester_assert_uint_eq(response2[i], response2[i + 16]); + } + for (unsigned i = 8; i < 16; i++) { + cester_assert_uint_eq(0, response2[i]); + } + for (unsigned i = 0; i < 16; i++) { + cester_assert_uint_eq(response3[i], response3[i + 16]); + } + cester_assert_uint_eq(2, response3[0]); + cester_assert_uint_eq(1, response3[1]); + cester_assert_uint_eq(0x25, response3[2]); + for (unsigned i = 3; i < 16; i++) { + cester_assert_uint_eq(0, response3[i]); + } + ramsyscall_printf("cdlId reading too much data, ack in %ius, complete in %ius\n", ackTime, completeTime); + ramsyscall_printf("Full response:\n%02x %02x %02x %02x %02x %02x %02x %02x\n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + response2[0], response2[1], response2[2], response2[3], + response2[4], response2[5], response2[6], response2[7], + response2[8], response2[9], response2[10], response2[11], + response2[12], response2[13], response2[14], response2[15], + response2[16], response2[17], response2[18], response2[19], + response2[20], response2[21], response2[22], response2[23], + response2[24], response2[25], response2[26], response2[27], + response2[28], response2[29], response2[30], response2[31]); + ramsyscall_printf("cdlGetTN reading too much data, full response:\n%02x %02x %02x %02x %02x %02x %02x %02x\n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n" + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + response3[0], response3[1], response3[2], response3[3], + response3[4], response3[5], response3[6], response3[7], + response3[8], response3[9], response3[10], response3[11], + response3[12], response3[13], response3[14], response3[15], + response3[16], response3[17], response3[18], response3[19], + response3[20], response3[21], response3[22], response3[23], + response3[24], response3[25], response3[26], response3[27], + response3[28], response3[29], response3[30], response3[31]); +) From aae23e7571b5964d4f771b525d9db8cbe3346b48 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 3 Mar 2024 22:23:17 -0800 Subject: [PATCH 178/185] Making buffer overrun test pass. --- src/core/cdrom.cc | 2 +- src/core/cdrom.h | 5 ++++- src/mips/tests/cdrom/cdlid.c | 1 - 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/cdrom.cc b/src/core/cdrom.cc index 0ba8f75a7..97af2b159 100644 --- a/src/core/cdrom.cc +++ b/src/core/cdrom.cc @@ -351,7 +351,7 @@ class CDRomImpl final : public PCSX::CDRom { The result register is not empty when this bit is high. At this time, the host can read the result register. */ - uint8_t v5 = !m_responseFifo[0].isPayloadEmpty() ? 0x20 : 0; + uint8_t v5 = !m_responseFifo[0].isPayloadAtEnd() ? 0x20 : 0; /* bit 4: PRMWRDY (parameter write ready) The PARAMETER register is not full when this bit is high. At this time, the host writes data into the diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 32ddb5a4d..13dfed6da 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -164,7 +164,8 @@ class CDRom { bool hasValue = false; uint8_t payloadSize = 0; uint8_t payloadIndex = 0; - bool isPayloadEmpty() const { return payloadSize == payloadIndex; } + bool isPayloadAtEnd() const { return payloadIndex == payloadSize; } + bool isPayloadEmpty() const { return payloadSize <= payloadIndex; } bool isPayloadFull() const { return payloadSize == sizeof(payload); } bool empty() const { return valueEmpty() && isPayloadEmpty(); } bool valueEmpty() const { return !hasValue || valueRead; } @@ -189,9 +190,11 @@ class CDRom { } uint8_t getValue() const { return valueRead ? 0 : value; } uint8_t readPayloadByte() { + while (payloadIndex >= 16) payloadIndex -= 16; if (payloadIndex < payloadSize) { return payload[payloadIndex++]; } + payloadIndex++; return 0; } }; diff --git a/src/mips/tests/cdrom/cdlid.c b/src/mips/tests/cdrom/cdlid.c index 791ec677a..bd89432af 100644 --- a/src/mips/tests/cdrom/cdlid.c +++ b/src/mips/tests/cdrom/cdlid.c @@ -144,7 +144,6 @@ CESTER_TEST(cdlIdReadsTooMuchThencdlGetTN, test_instance, CDROM_REG0 = 1; uint8_t cause2b = CDROM_REG3_UC; - CDROM_REG0 = 0; CDROM_REG1 = CDL_GETTN; From 71ba79b03a00281c7dfa7b12cd0e9347a7009af7 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 3 Mar 2024 22:33:45 -0800 Subject: [PATCH 179/185] Tweaking test a bit more. --- src/mips/tests/cdrom/cdlid.c | 51 ++++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cdlid.c b/src/mips/tests/cdrom/cdlid.c index bd89432af..4bd27dc8f 100644 --- a/src/mips/tests/cdrom/cdlid.c +++ b/src/mips/tests/cdrom/cdlid.c @@ -112,7 +112,54 @@ CESTER_TEST(cdlIdTooManyArgs, test_instance, ramsyscall_printf("Basic cdlId with too many args, errored in %ius\n", errorTime); ) -CESTER_TEST(cdlIdReadsTooMuchThencdlGetTN, test_instance, +CESTER_TEST(cdlIdReadsTooMuch, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETID; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[12]; + for (unsigned i = 0; i < 12; i++) { + response2[i] = CDROM_REG1; + } + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x38, ctrl4); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + ramsyscall_printf("cdlId reading too much data, ack in %ius, complete in %ius\n", ackTime, completeTime); +) + +CESTER_TEST(cdlIdReadsWayTooMuchThencdlGetTN, test_instance, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -181,7 +228,7 @@ CESTER_TEST(cdlIdReadsTooMuchThencdlGetTN, test_instance, for (unsigned i = 3; i < 16; i++) { cester_assert_uint_eq(0, response3[i]); } - ramsyscall_printf("cdlId reading too much data, ack in %ius, complete in %ius\n", ackTime, completeTime); + ramsyscall_printf("cdlId reading way too much data, ack in %ius, complete in %ius\n", ackTime, completeTime); ramsyscall_printf("Full response:\n%02x %02x %02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x %02x %02x %02x %02x\n" "%02x %02x %02x %02x %02x %02x %02x %02x\n" From 0d19019807ae11ceae2c28de372cab4d6baecdc3 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 3 Mar 2024 22:40:59 -0800 Subject: [PATCH 180/185] Better tweak. --- src/mips/tests/cdrom/cdlid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cdlid.c b/src/mips/tests/cdrom/cdlid.c index 4bd27dc8f..b7d226ed3 100644 --- a/src/mips/tests/cdrom/cdlid.c +++ b/src/mips/tests/cdrom/cdlid.c @@ -136,8 +136,8 @@ CESTER_TEST(cdlIdReadsTooMuch, test_instance, uint32_t completeTime = waitCDRomIRQ(); uint8_t cause2 = ackCDRomCause(); uint8_t ctrl3 = CDROM_REG0 & ~3; - uint8_t response2[12]; - for (unsigned i = 0; i < 12; i++) { + uint8_t response2[17]; + for (unsigned i = 0; i < 17; i++) { response2[i] = CDROM_REG1; } uint8_t ctrl4 = CDROM_REG0 & ~3; From 120e856f568e02f86cb3123a9b34fb794ef976c7 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 4 Mar 2024 17:46:05 -0800 Subject: [PATCH 181/185] Being a bit more annoying with this test. --- src/mips/tests/cdrom/cdlid.c | 87 +++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/src/mips/tests/cdrom/cdlid.c b/src/mips/tests/cdrom/cdlid.c index b7d226ed3..f91fb8716 100644 --- a/src/mips/tests/cdrom/cdlid.c +++ b/src/mips/tests/cdrom/cdlid.c @@ -112,7 +112,72 @@ CESTER_TEST(cdlIdTooManyArgs, test_instance, ramsyscall_printf("Basic cdlId with too many args, errored in %ius\n", errorTime); ) -CESTER_TEST(cdlIdReadsTooMuch, test_instance, +CESTER_TEST(cdlIdReads12BytesThenGetTN, test_instance, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + initializeTime(); + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETID; + + uint32_t ackTime = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[12]; + for (unsigned i = 0; i < 12; i++) { + response2[i] = CDROM_REG1; + } + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETTN; + + waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl5 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x38, ctrl4); + cester_assert_uint_eq(0x18, ctrl5); + cester_assert_uint_ge(ackTime, 500); + cester_assert_uint_lt(ackTime, 7000); + cester_assert_uint_eq(2, response3[0]); + cester_assert_uint_eq(1, response3[1]); + cester_assert_uint_eq(0x25, response3[2]); + cester_assert_uint_eq(3, responseSize3); + ramsyscall_printf("cdlId reading 12 bytes then cdlGetTN, ack in %ius, complete in %ius\n", ackTime, completeTime); +) + +CESTER_TEST(cdlIdReads17BytesThenGetTN, test_instance, int resetDone = resetCDRom(); if (!resetDone) { cester_assert_true(resetDone); @@ -144,19 +209,37 @@ CESTER_TEST(cdlIdReadsTooMuch, test_instance, CDROM_REG0 = 1; uint8_t cause2b = CDROM_REG3_UC; + CDROM_REG0 = 0; + CDROM_REG1 = CDL_GETTN; + + waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl5 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + cester_assert_uint_eq(3, cause1); cester_assert_uint_eq(2, cause2); + cester_assert_uint_eq(3, cause3); cester_assert_uint_eq(0xe0, cause1b); cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0xe0, cause3b); cester_assert_uint_eq(2, response1[0]); cester_assert_uint_eq(1, responseSize1); cester_assert_uint_eq(0x38, ctrl1); cester_assert_uint_eq(0x18, ctrl2); cester_assert_uint_eq(0x38, ctrl3); cester_assert_uint_eq(0x38, ctrl4); + cester_assert_uint_eq(0x18, ctrl5); cester_assert_uint_ge(ackTime, 500); cester_assert_uint_lt(ackTime, 7000); - ramsyscall_printf("cdlId reading too much data, ack in %ius, complete in %ius\n", ackTime, completeTime); + cester_assert_uint_eq(2, response3[0]); + cester_assert_uint_eq(1, response3[1]); + cester_assert_uint_eq(0x25, response3[2]); + cester_assert_uint_eq(3, responseSize3); + ramsyscall_printf("cdlId reading 17 bytes then cdlGetTN, ack in %ius, complete in %ius\n", ackTime, completeTime); ) CESTER_TEST(cdlIdReadsWayTooMuchThencdlGetTN, test_instance, From 8ff20720dee2f663762185060bdafc015f5cafb5 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 4 Mar 2024 18:49:03 -0800 Subject: [PATCH 182/185] Making test pass. --- src/core/cdrom.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/core/cdrom.h b/src/core/cdrom.h index 13dfed6da..44fab7364 100644 --- a/src/core/cdrom.h +++ b/src/core/cdrom.h @@ -158,14 +158,15 @@ class CDRom { uint8_t m_lastLocL[8] = {0}; struct QueueElement { - uint8_t value; uint8_t payload[16]; + uint8_t value; bool valueRead = false; bool hasValue = false; + bool hitMax = false; uint8_t payloadSize = 0; uint8_t payloadIndex = 0; - bool isPayloadAtEnd() const { return payloadIndex == payloadSize; } - bool isPayloadEmpty() const { return payloadSize <= payloadIndex; } + bool isPayloadAtEnd() const { return payloadIndex == payloadSize; } + bool isPayloadEmpty() const { return (payloadSize == 0) || hitMax; } bool isPayloadFull() const { return payloadSize == sizeof(payload); } bool empty() const { return valueEmpty() && isPayloadEmpty(); } bool valueEmpty() const { return !hasValue || valueRead; } @@ -191,11 +192,12 @@ class CDRom { uint8_t getValue() const { return valueRead ? 0 : value; } uint8_t readPayloadByte() { while (payloadIndex >= 16) payloadIndex -= 16; + uint8_t r = 0; if (payloadIndex < payloadSize) { - return payload[payloadIndex++]; + r = payload[payloadIndex]; } - payloadIndex++; - return 0; + if (++payloadIndex == payloadSize) hitMax = true; + return r; } }; From 69fa64e90fab165199ef88526c3c1d426cbabf57 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 4 Mar 2024 20:25:30 -0800 Subject: [PATCH 183/185] Adding hexdump utility. --- src/mips/tests/cdrom/cester-hw.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/mips/tests/cdrom/cester-hw.c b/src/mips/tests/cdrom/cester-hw.c index 5563b238e..4c5736597 100644 --- a/src/mips/tests/cdrom/cester-hw.c +++ b/src/mips/tests/cdrom/cester-hw.c @@ -32,6 +32,29 @@ SOFTWARE. #include CESTER_BODY( + static void hexdump(const void* data_, unsigned size) { + const uint8_t* data = (const uint8_t*)data_; + char ascii[17]; + ascii[16] = 0; + for (unsigned i = 0; i < size; i++) { + if (i % 16 == 0) ramsyscall_printf("%08x |", i); + ramsyscall_printf("%02X ", data[i]); + ascii[i % 16] = data[i] >= ' ' && data[i] <= '~' ? data[i] : '.'; + unsigned j = i + 1; + if ((j % 8 == 0) || (j == size)) { + ramsyscall_printf(" "); + if (j % 16 == 0) { + ramsyscall_printf("| %s \n", ascii); + } else if (j == size) { + ascii[j % 16] = 0; + if (j % 16 <= 8) ramsyscall_printf(" "); + for (j %= 16; j < 16; j++) ramsyscall_printf(" "); + ramsyscall_printf("| %s \n", ascii); + } + } + } + } + static int s_interruptsWereEnabled = 0; static uint16_t s_oldMode = 0; static uint32_t s_lastHSyncCounter = 0; From 6b43700567c9a611e361034d86f83c5fa32b216c Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Mon, 4 Mar 2024 20:25:57 -0800 Subject: [PATCH 184/185] Adding full mode2 read test. --- src/mips/tests/cdrom/cdlreadn.c | 139 ++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/src/mips/tests/cdrom/cdlreadn.c b/src/mips/tests/cdrom/cdlreadn.c index 922eed1c7..bf6a0fa74 100644 --- a/src/mips/tests/cdrom/cdlreadn.c +++ b/src/mips/tests/cdrom/cdlreadn.c @@ -498,6 +498,145 @@ CESTER_TEST(cdlReadN2xwithDMA, test_instances, ramsyscall_printf("Basic single full sector readN @2x with DMA at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); ) +CESTER_TEST(cdlReadN2xwithDMAMode02, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0xa0); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int setLocDone = setLoc(0, 2, 0x16); + if (!setLocDone) { + cester_assert_true(setLocDone); + return; + } + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_READN; + uint32_t ackTime1 = waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response1[16]; + uint8_t responseSize1 = readResponse(response1); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause1b = CDROM_REG3_UC; + + uint32_t readyTime = waitCDRomIRQ() - ackTime1; + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl3 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl4 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + initializeTime(); + uint8_t sector[2340]; + + CDROM_REG0 = 0; + CDROM_REG3 = 0x80; + + uint32_t dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x00880000; + DICR = dicr; + DPCR |= 0x8000; + DMA_CTRL[DMA_CDROM].MADR = (uintptr_t)sector; + DMA_CTRL[DMA_CDROM].BCR = (2340 >> 2) | 0x10000; + DMA_CTRL[DMA_CDROM].CHCR = 0x11000000; + + while ((DMA_CTRL[DMA_CDROM].CHCR & 0x01000000) != 0); + dicr = DICR; + dicr &= 0x00ffffff; + dicr |= 0x88000000; + DICR = dicr; + CDROM_REG3 = 0; + uint32_t readTime = updateTime(); + + initializeTime(); + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PAUSE; + uint32_t ackTime2 = waitCDRomIRQ(); + uint8_t cause3 = ackCDRomCause(); + uint8_t ctrl5 = CDROM_REG0 & ~3; + uint8_t response3[16]; + uint8_t responseSize3 = readResponse(response3); + uint8_t ctrl6 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause3b = CDROM_REG3_UC; + + uint32_t completeTime = waitCDRomIRQ() - ackTime2; + uint8_t cause4 = ackCDRomCause(); + uint8_t ctrl7 = CDROM_REG0 & ~3; + uint8_t response4[16]; + uint8_t responseSize4 = readResponse(response4); + uint8_t ctrl8 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause4b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(0xe0, cause1b); + cester_assert_uint_eq(1, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(3, cause3); + cester_assert_uint_eq(0xe0, cause3b); + cester_assert_uint_eq(2, cause4); + cester_assert_uint_eq(0xe0, cause4b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(0x38, ctrl3); + cester_assert_uint_eq(0x18, ctrl4); + cester_assert_uint_eq(0x38, ctrl5); + cester_assert_uint_eq(0x18, ctrl6); + cester_assert_uint_eq(0x38, ctrl7); + cester_assert_uint_eq(0x18, ctrl8); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(0x22, response2[0]); + cester_assert_uint_eq(1, responseSize2); + cester_assert_uint_eq(0x22, response3[0]); + cester_assert_uint_eq(1, responseSize3); + cester_assert_uint_eq(2, response4[0]); + cester_assert_uint_eq(1, responseSize4); + cester_assert_uint_ge(ackTime1, 500); + cester_assert_uint_lt(ackTime1, 7000); + cester_assert_uint_ge(ackTime2, 500); + cester_assert_uint_lt(ackTime2, 7000); + // Switching speed is roughly 650ms for the speed up, + // and then this also contains the seeking time, and + // the time to read the first sector, which is 6.66ms + cester_assert_uint_ge(readyTime, 500000); + // Pausing at 2x is ~35ms + cester_assert_uint_ge(completeTime, 32500); + cester_assert_uint_eq(0x00, sector[0]); + cester_assert_uint_eq(0x02, sector[1]); + cester_assert_uint_eq(0x16, sector[2]); + cester_assert_uint_eq(0x02, sector[3]); + cester_assert_uint_eq(0x00, sector[4]); + cester_assert_uint_eq(0x00, sector[5]); + cester_assert_uint_eq(0x08, sector[6]); + cester_assert_uint_eq(0x00, sector[7]); + cester_assert_uint_eq(0x00, sector[8]); + cester_assert_uint_eq(0x00, sector[9]); + cester_assert_uint_eq(0x08, sector[10]); + cester_assert_uint_eq(0x00, sector[11]); + cester_assert_uint_eq(1, sector[12]); + cester_assert_uint_eq('C', sector[13]); + cester_assert_uint_eq('D', sector[14]); + cester_assert_uint_eq('0', sector[15]); + cester_assert_uint_eq('0', sector[16]); + cester_assert_uint_eq('1', sector[17]); + ramsyscall_printf("Basic single full sector readN @2x in 2340 mode with DMA at 00:02:16, ack1 in %ius, ready in %ius, read in %ius, ack2 in %ius, complete in %ius\n", ackTime1, readyTime, readTime, ackTime2, completeTime); +) + CESTER_TEST(cdlReadN2xRunaway, test_instances, int resetDone = resetCDRom(); if (!resetDone) { From b30f74beefb9b5dbcacd7e12f569848700ce2cd6 Mon Sep 17 00:00:00 2001 From: Nicolas Pixel Noble Date: Sun, 11 Aug 2024 22:14:45 -0700 Subject: [PATCH 185/185] Adding some CDDA tests. --- src/mips/tests/cdrom/cdrom.c | 1 + src/mips/tests/cdrom/playing.c | 225 +++++++++++++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 src/mips/tests/cdrom/playing.c diff --git a/src/mips/tests/cdrom/cdrom.c b/src/mips/tests/cdrom/cdrom.c index bc925fcd4..c7d994c71 100644 --- a/src/mips/tests/cdrom/cdrom.c +++ b/src/mips/tests/cdrom/cdrom.c @@ -57,6 +57,7 @@ SOFTWARE. #include "cdltest.c" #include "invalid.c" #include "misc.c" +#include "playing.c" #include "race.c" #include "reading.c" #else diff --git a/src/mips/tests/cdrom/playing.c b/src/mips/tests/cdrom/playing.c new file mode 100644 index 000000000..60384c5a7 --- /dev/null +++ b/src/mips/tests/cdrom/playing.c @@ -0,0 +1,225 @@ +/* + +MIT License + +Copyright (c) 2024 PCSX-Redux authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +// clang-format off + +CESTER_TEST(simplePlayingUntilEnd, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x00); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int seekDone = seekPTo(0x71, 0x27, 0); + + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PLAY; + uint8_t response1[16]; + waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t responseSize1 = readResponse(response1); + + initializeTime(); + uint32_t time1 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(4, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + // Should finish in 1640ms to 1960ms. + cester_assert_uint_ge(time1, 1640000); + cester_assert_uint_lt(time1, 1960000); + ramsyscall_printf("Simple Playing until end, finished in %ius\n", time1); +) + +CESTER_TEST(simplePlayingUntilEndDoubleTime, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x80); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int seekDone = seekPTo(0x71, 0x27, 0); + + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PLAY; + uint8_t response1[16]; + waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + uint8_t responseSize1 = readResponse(response1); + + initializeTime(); + uint32_t time1 = waitCDRomIRQ(); + uint8_t cause2 = ackCDRomCause(); + uint8_t ctrl1 = CDROM_REG0 & ~3; + uint8_t response2[16]; + uint8_t responseSize2 = readResponse(response2); + uint8_t ctrl2 = CDROM_REG0 & ~3; + CDROM_REG0 = 1; + uint8_t cause2b = CDROM_REG3_UC; + + cester_assert_uint_eq(3, cause1); + cester_assert_uint_eq(4, cause2); + cester_assert_uint_eq(0xe0, cause2b); + cester_assert_uint_eq(0x38, ctrl1); + cester_assert_uint_eq(0x18, ctrl2); + cester_assert_uint_eq(2, response1[0]); + cester_assert_uint_eq(1, responseSize1); + cester_assert_uint_eq(2, response2[0]); + cester_assert_uint_eq(1, responseSize2); + // Should finish in 820ms to 980ms. + cester_assert_uint_ge(time1, 820000); + cester_assert_uint_lt(time1, 980000); + ramsyscall_printf("Simple Playing until end, Double Time, finished in %ius\n", time1); +) + +CESTER_TEST(simplePlayingUntilEndWithReport, test_instances, + int resetDone = resetCDRom(); + if (!resetDone) { + cester_assert_true(resetDone); + return; + } + + int setModeDone = setMode(0x04); + if (!setModeDone) { + cester_assert_true(setModeDone); + return; + } + + int seekDone = seekPTo(0x71, 0x26, 0); + + if (!seekDone) { + cester_assert_true(seekDone); + return; + } + + CDROM_REG0 = 0; + CDROM_REG1 = CDL_PLAY; + uint8_t response[16]; + waitCDRomIRQ(); + uint8_t cause1 = ackCDRomCause(); + readResponse(response); + + uint8_t causes[32]; + uint8_t responseSizes[32]; + uint8_t responses[32 * 16]; + + __builtin_memset(causes, 0, sizeof(causes)); + __builtin_memset(responseSizes, 0, sizeof(responseSizes)); + + unsigned count; + + for (count = 0; count < 32; count++) { + waitCDRomIRQ(); + uint8_t cause = ackCDRomCause(); + causes[count] = cause; + responseSizes[count] = readResponse(responses + count * 16); + if (cause != 1) break; + } + + for (unsigned i = 0; i < count; i++) { + cester_assert_uint_eq(1, causes[i]); + cester_assert_uint_eq(8, responseSizes[i]); + } + cester_assert_uint_eq(4, causes[count]); + cester_assert_uint_eq(1, responseSizes[count]); + cester_assert_uint_eq(3, cause1); + cester_assert_uint_ge(count, 15); + cester_assert_uint_lt(count, 17); + if (count >= 15) { + unsigned offset = count - 15; + unsigned upCount = 0; + for (unsigned i = offset; i < count; i++) { + // stat + cester_assert_uint_eq(0x82, responses[i * 16 + 0]); + // track + cester_assert_uint_eq(0x25, responses[i * 16 + 1]); + // index + cester_assert_uint_eq(0x01, responses[i * 16 + 2]); + unsigned index = i - offset; + if ((index & 1) == 0) { + // absolute minute time + cester_assert_uint_eq(0x71, responses[i * 16 + 3]); + } else { + // relative minute time + cester_assert_uint_eq(0, responses[i * 16 + 3]); + } + static uint8_t seconds[15] = { 0x26, 0x81, 0x27, 0x81, 0x27, 0x82, 0x27, 0x82, 0x27, 0x82, 0x28, 0x82, 0x28, 0x83, 0x28 }; + cester_assert_uint_eq(seconds[index], responses[i * 16 + 4]); + static uint8_t frames[15] = { 0x60, 0x40, 0x00, 0x55, 0x20, 0x00, 0x40, 0x20, 0x60, 0x40, 0x00, 0x55, 0x20, 0x00, 0x40 }; + // This report might wobble a bit, but the above values ought to be close enough to our most likely values. + cester_assert_uint_ge(responses[i * 16 + 5], frames[index]); + cester_assert_uint_le(responses[i * 16 + 5], frames[index] + 1); + uint16_t peak = (responses[i * 16 + 7] << 8) | responses[i * 16 + 6]; + uint16_t flag = peak & 0x8000; + peak &= 0x7fff; + cester_assert_uint_eq(0x619b, peak); + if (flag == 0x8000) upCount++; + } + cester_assert_uint_ge(upCount, 6); + cester_assert_uint_le(upCount, 8); + } + ramsyscall_printf("Simple Playing until end with reports:\n"); + for (unsigned i = 0; i < count; i++) { + ramsyscall_printf(" - Response[%i] = %02x %02x %02x %02x %02x %02x %02x %02x\n", i, + responses[i * 16 + 0], responses[i * 16 + 1], responses[i * 16 + 2], responses[i * 16 + 3], + responses[i * 16 + 4], responses[i * 16 + 5], responses[i * 16 + 6], responses[i * 16 + 7]); + } +)