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;
// MM must be BCD, SS must be BCD and <0x60, FF must be BCD and <0x75
if (((cdr.Param[0] & 0x0F) > 0x09) || (cdr.Param[0] > 0x99) || ((cdr.Param[1] & 0x0F) > 0x09) || (cdr.Param[1] >= 0x60) || ((cdr.Param[2] & 0x0F) > 0x09) || (cdr.Param[2] >= 0x75))
{
- CDR_LOG("Invalid/out of range seek to %02X:%02X:%02X\n", cdr.Param[0], cdr.Param[1], cdr.Param[2]);
+ CDR_LOG_I("Invalid/out of range seek to %02X:%02X:%02X\n", cdr.Param[0], cdr.Param[1], cdr.Param[2]);
error = ERROR_INVALIDARG;
goto set_error;
}
case CdlSeekL + CMD_PART2:
case CdlSeekP + CMD_PART2:
SetPlaySeekRead(cdr.StatP, 0);
+ cdr.Result[0] = cdr.StatP;
cdr.Stat = Complete;
Find_CurTrack(cdr.SetSectorPlay);
case CdlReadN:
case CdlReadS:
+ if (cdr.Reading && !cdr.SetlocPending)
+ break;
+
Find_CurTrack(cdr.SetlocPending ? cdr.SetSector : cdr.SetSectorPlay);
if ((cdr.Mode & MODE_CDDA) && cdr.CurTrack > 1)
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;
}
switch (chcr & 0x71000000) {
case 0x11000000:
ptr = (u8 *)PSXM(madr);
- if (ptr == NULL) {
+ if (ptr == INVALID_PTR) {
CDR_LOG_I("psxDma3() Log: *** DMA 3 *** NULL Pointer!\n");
break;
}