CDR_LOG("ReadTrack *** %02x:%02x:%02x\n", tmp[0], tmp[1], tmp[2]);
read_ok = CDR_readTrack(tmp);
- memcpy(cdr.Prev, tmp, 3);
+ if (read_ok)
+ memcpy(cdr.Prev, tmp, 3);
if (CheckSBI(time))
return read_ok;
return seekTime;
}
+static u32 cdrAlignTimingHack(u32 cycles)
+{
+ /*
+ * timing hack for T'ai Fu - Wrath of the Tiger:
+ * The game has a bug where it issues some cdc commands from a low priority
+ * vint handler, however there is a higher priority default bios handler
+ * that acks the vint irq and returns, so game's handler is not reached
+ * (see bios irq handler chains at e004 and the game's irq handling func
+ * at 80036810). For the game to work, vint has to arrive after the bios
+ * vint handler rejects some other irq (of which only cd and rcnt2 are
+ * active), but before the game's handler loop reads I_STAT. The time
+ * window for this is quite small (~1k cycles of so). Apparently this
+ * somehow happens naturally on the real hardware.
+ */
+ u32 vint_rel = rcnts[3].cycleStart + 63000 - psxRegs.cycle;
+ vint_rel += PSXCLK / 60;
+ while ((s32)(vint_rel - cycles) < 0)
+ vint_rel += PSXCLK / 60;
+ return vint_rel;
+}
+
static void cdrUpdateTransferBuf(const u8 *buf);
static void cdrReadInterrupt(void);
static void cdrPrepCdda(s16 *buf, int samples);
void cdrInterrupt(void) {
int start_rotating = 0;
int error = 0;
- unsigned int seekTime = 0;
+ u32 cycles, seekTime = 0;
u32 second_resp_time = 0;
const void *buf;
u8 ParamC;
ReadTrack(cdr.SetSectorPlay);
cdr.LocL[0] = LOCL_INVALID;
- CDRPLAYREAD_INT(((cdr.Mode & 0x80) ? (cdReadTime) : cdReadTime * 2) + seekTime, 1);
+ cycles = (cdr.Mode & 0x80) ? cdReadTime : cdReadTime * 2;
+ cycles += seekTime;
+ cycles = cdrAlignTimingHack(cycles);
+ CDRPLAYREAD_INT(cycles, 1);
SetPlaySeekRead(cdr.StatP, STATUS_SEEK);
start_rotating = 1;
if (!read_ok) {
CDR_LOG_I("cdrReadInterrupt() Log: err\n");
- memset(cdr.Transfer, 0, DATA_SIZE);
cdrReadInterruptSetResult(cdr.StatP | STATUS_ERROR);
return;
}
}
unsigned char cdrRead2(void) {
- unsigned char ret = 0;
+ unsigned char ret = cdr.Transfer[0x920];
if (cdr.FifoOffset < cdr.FifoSize)
ret = cdr.Transfer[cdr.FifoOffset++];
{
memcpy(ptr, cdr.Transfer + cdr.FifoOffset, size);
cdr.FifoOffset += size;
- psxCpu->Clear(madr, size / 4);
}
- if (size < cdsize)
+ if (size < cdsize) {
CDR_LOG_I("cdrom: dma3 %d/%d\n", size, cdsize);
+ memset(ptr + size, cdr.Transfer[0x920], cdsize - size);
+ }
+ psxCpu->Clear(madr, cdsize / 4);
CDRDMA_INT((cdsize/4) * 24);
if (Mode == 0) {
getCdInfo();
- cdr.FifoOffset = tmp;
+ cdr.FifoOffset = tmp < DATA_SIZE ? tmp : DATA_SIZE;
cdr.FifoSize = (cdr.Mode & 0x20) ? 2340 : 2048 + 12;
// read right sub data