X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=pcsx_rearmed.git;a=blobdiff_plain;f=libpcsxcore%2Fcdrom.c;h=95e1f05f1e2ccfe9e3a3d58997509a3caaa06728;hp=f227b1ba531be02b9713035d8eca9f2857644995;hb=80f91a20e39eed8294b125af199c504cf8519d45;hpb=73b29eebea762ea3af6e27060e2b20cd8a58da91 diff --git a/libpcsxcore/cdrom.c b/libpcsxcore/cdrom.c index f227b1ba..95e1f05f 100644 --- a/libpcsxcore/cdrom.c +++ b/libpcsxcore/cdrom.c @@ -108,6 +108,7 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 }; #define MODE_STRSND (1<<6) // 0x40 ADPCM on/off #define MODE_SIZE_2340 (1<<5) // 0x20 #define MODE_SIZE_2328 (1<<4) // 0x10 +#define MODE_SIZE_2048 (0<<4) // 0x00 #define MODE_SF (1<<3) // 0x08 channel on/off #define MODE_REPORT (1<<2) // 0x04 #define MODE_AUTOPAUSE (1<<1) // 0x02 @@ -124,12 +125,18 @@ unsigned char Test23[] = { 0x43, 0x58, 0x44, 0x32, 0x39 ,0x34, 0x30, 0x51 }; #define STATUS_ERROR (1<<0) // 0x01 - // 1x = 75 sectors per second // PSXCLK = 1 sec in the ps // so (PSXCLK / 75) = cdr read time (linuzappz) #define cdReadTime (PSXCLK / 75) +enum drive_state { + DRIVESTATE_STANDBY = 0, + DRIVESTATE_LID_OPEN, + DRIVESTATE_RESCAN_CD, + DRIVESTATE_PREPARE_CD, +}; + // for cdr.Seeked enum seeked_state { SEEK_PENDING = 0, @@ -218,165 +225,76 @@ static void setIrq(void) psxHu32ref(0x1070) |= SWAP32((u32)0x4); } +// 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 cdrLidSeekInterrupt() { - // turn back on checking - if( cdr.LidCheck == 0x10 ) - { - cdr.LidCheck = 0; - } - - // official lid close - else if( cdr.LidCheck == 0x30 ) - { - // GS CDX 3.3: $13 - cdr.StatP |= STATUS_ROTATING; - - - // GS CDX 3.3 - ~50 getlocp tries - CDRLID_INT( cdReadTime * 3 ); - cdr.LidCheck = 0x40; - } - - // turn off ready - else if( cdr.LidCheck == 0x40 ) - { - // GS CDX 3.3: $01 - cdr.StatP &= ~STATUS_SHELLOPEN; - cdr.StatP &= ~STATUS_ROTATING; - - - // GS CDX 3.3 - ~50 getlocp tries - CDRLID_INT( cdReadTime * 3 ); - cdr.LidCheck = 0x50; - } - - // now seek - else if( cdr.LidCheck == 0x50 ) - { - // GameShark Lite: Start seeking ($42) - cdr.StatP |= STATUS_SEEK; - cdr.StatP |= STATUS_ROTATING; - cdr.StatP &= ~STATUS_ERROR; - - - CDRLID_INT( cdReadTime * 3 ); - cdr.LidCheck = 0x60; - } - - // done = cd ready - else if( cdr.LidCheck == 0x60 ) - { - // GameShark Lite: Seek detection done ($02) + switch (cdr.DriveState) { + default: + case DRIVESTATE_STANDBY: cdr.StatP &= ~STATUS_SEEK; - cdr.LidCheck = 0; - } -} - -static void Check_Shell( int Irq ) -{ - // check case open/close - if (cdr.LidCheck > 0) - { - CDR_LOG( "LidCheck\n" ); + if (CDR_getStatus(&stat) == -1) + return; - // $20 = check lid state - if( cdr.LidCheck == 0x20 ) + if (stat.Status & STATUS_SHELLOPEN) { - u32 i; - - i = stat.Status; - if (CDR_getStatus(&stat) != -1) - { - // BIOS hangs + BIOS error messages - //if (stat.Type == 0xff) - //cdr.Stat = DiskError; - - // case now open - if (stat.Status & STATUS_SHELLOPEN) - { - // Vib Ribbon: pre-CD swap - StopCdda(); - - - // GameShark Lite: Death if DiskError happens - // - // Vib Ribbon: Needs DiskError for CD swap - - if (Irq != CdlNop) - { - cdr.Stat = DiskError; - - cdr.StatP |= STATUS_ERROR; - cdr.Result[0] |= STATUS_ERROR; - } - - // GameShark Lite: Wants -exactly- $10 - cdr.StatP |= STATUS_SHELLOPEN; - cdr.StatP &= ~STATUS_ROTATING; - - - CDRLID_INT( cdReadTime * 3 ); - cdr.LidCheck = 0x10; - - - // GS CDX 3.3 = $11 - } - - // case just closed - else if ( i & STATUS_SHELLOPEN ) - { - cdr.StatP |= STATUS_ROTATING; - - CheckCdrom(); - - - if( cdr.Stat == NoIntr ) - cdr.Stat = Acknowledge; + StopCdda(); + cdr.DriveState = DRIVESTATE_LID_OPEN; + CDRLID_INT(0x800); + } + break; - setIrq(); + case DRIVESTATE_LID_OPEN: + if (CDR_getStatus(&stat) == -1) + stat.Status &= ~STATUS_SHELLOPEN; - // begin close-seek-ready cycle - CDRLID_INT( cdReadTime * 3 ); - cdr.LidCheck = 0x30; + // 02, 12, 10 + if (!(cdr.StatP & STATUS_SHELLOPEN)) { + StopReading(); + cdr.StatP |= STATUS_SHELLOPEN; + // could generate error irq here, but real hardware + // only sometimes does that + // (not done when lots of commands are sent?) - // GameShark Lite: Wants -exactly- $42, then $02 - // GS CDX 3.3: Wants $11/$80, $13/$80, $01/$00 - } - - // case still closed - wait for recheck - else - { - CDRLID_INT( cdReadTime * 3 ); - cdr.LidCheck = 0x10; - } - } + CDRLID_INT(cdReadTime * 30); + break; } + else if (cdr.StatP & STATUS_ROTATING) { + cdr.StatP &= ~STATUS_ROTATING; + } + else if (!(stat.Status & STATUS_SHELLOPEN)) { + // closed now + CheckCdrom(); + // cdr.StatP STATUS_SHELLOPEN is "sticky" + // and is only cleared by CdlNop - // GS CDX: clear all values but #1,#2 - if( (cdr.LidCheck >= 0x30) || (cdr.StatP & STATUS_SHELLOPEN) ) - { - SetResultSize(16); - memset( cdr.Result, 0, 16 ); - - cdr.Result[0] = cdr.StatP; + cdr.DriveState = DRIVESTATE_RESCAN_CD; + CDRLID_INT(cdReadTime * 105); + break; + } + // recheck for close + CDRLID_INT(cdReadTime * 3); + break; - // GS CDX: special return value - if( cdr.StatP & STATUS_SHELLOPEN ) - { - cdr.Result[1] = 0x80; - } + case DRIVESTATE_RESCAN_CD: + cdr.StatP |= STATUS_ROTATING; + cdr.DriveState = DRIVESTATE_PREPARE_CD; + // this is very long on real hardware, over 6 seconds + // make it a bit faster here... + CDRLID_INT(cdReadTime * 150); + break; - if( cdr.Stat == NoIntr ) - cdr.Stat = Acknowledge; + case DRIVESTATE_PREPARE_CD: + cdr.StatP |= STATUS_SEEK; - setIrq(); - } + cdr.DriveState = DRIVESTATE_STANDBY; + CDRLID_INT(cdReadTime * 26); + break; } } @@ -617,7 +535,7 @@ void cdrInterrupt() { SetResultSize(1); cdr.StatP |= STATUS_ROTATING; cdr.Result[0] = cdr.StatP; - cdr.Stat = Acknowledge; + cdr.Stat = Acknowledge; break; case CdlNop: @@ -625,7 +543,8 @@ void cdrInterrupt() { cdr.Result[0] = cdr.StatP; cdr.Stat = Acknowledge; - if (cdr.LidCheck == 0) cdr.LidCheck = 0x20; + if (cdr.DriveState != DRIVESTATE_LID_OPEN) + cdr.StatP &= ~STATUS_SHELLOPEN; break; case CdlSetloc: @@ -746,8 +665,6 @@ void cdrInterrupt() { cdr.Result[0] = cdr.StatP; cdr.Stat = Complete; // cdr.Stat = Acknowledge; - - if (cdr.LidCheck == 0) cdr.LidCheck = 0x20; break; case CdlPause: @@ -852,11 +769,6 @@ void cdrInterrupt() { break; case CdlGetTN: - // 5-Star Racing: don't stop CDDA - // - // Vib Ribbon: CD swap - StopReading(); - cdr.CmdProcess = 0; SetResultSize(3); cdr.StatP |= STATUS_ROTATING; @@ -941,34 +853,23 @@ void cdrInterrupt() { case CdlID + 0x20: SetResultSize(8); + cdr.Result[0] = cdr.StatP; + cdr.Result[1] = 0; + cdr.Result[2] = 0; + cdr.Result[3] = 0; - if (CDR_getStatus(&stat) == -1) { - cdr.Result[0] = 0x00; // 0x08 and cdr.Result[1]|0x10 : audio cd, enters cd player - cdr.Result[1] = 0x80; // 0x80 leads to the menu in the bios, else loads CD + // 0x10 - audio | 0x40 - disk missing | 0x80 - unlicensed + if (CDR_getStatus(&stat) == -1 || stat.Type == 0 || stat.Type == 0xff) { + cdr.Result[1] = 0xc0; } else { - if (stat.Type == 2) { - // Music CD - cdr.Result[0] = 0x08; - cdr.Result[1] = 0x10; - + if (stat.Type == 2) + cdr.Result[1] |= 0x10; + if (CdromId[0] == '\0') cdr.Result[1] |= 0x80; - } - else { - // Data CD - if (CdromId[0] == '\0') { - cdr.Result[0] = 0x00; - cdr.Result[1] = 0x80; - } - else { - cdr.Result[0] = 0x08; - cdr.Result[1] = 0x00; - } - } } + cdr.Result[0] |= (cdr.Result[1] >> 4) & 0x08; - cdr.Result[2] = 0x00; - cdr.Result[3] = 0x00; strncpy((char *)&cdr.Result[4], "PCSX", 4); cdr.Stat = Complete; break; @@ -1000,7 +901,7 @@ void cdrInterrupt() { cdr.StatP |= STATUS_ROTATING; cdr.Result[0] = cdr.StatP; cdr.Stat = Acknowledge; - AddIrqQueue(CdlReadToc + 0x20, 0x800); + AddIrqQueue(CdlReadToc + 0x20, cdReadTime * 16); break; case CdlReadToc + 0x20: @@ -1061,21 +962,80 @@ void cdrInterrupt() { break; } - Check_Shell( Irq ); + if (Irq != CdlNop) { + switch (cdr.DriveState) { + case DRIVESTATE_LID_OPEN: + case DRIVESTATE_RESCAN_CD: + case DRIVESTATE_PREPARE_CD: + SetResultSize(2); + cdr.Result[0] = cdr.StatP | STATUS_ERROR; + cdr.Result[1] = 0x80; + cdr.Stat = DiskError; + break; + } + } cdr.ParamC = 0; setIrq(); #ifdef CDR_LOG_CMD_IRQ - SysPrintf("cdrInterrupt() Log: CDR Interrupt IRQ %d %02x: ", - cdr.Stat != NoIntr && cdr.Reg2 != 0x18, Irq); + SysPrintf("IRQ %d cmd %02x stat %02x: ", + !!(cdr.Stat & cdr.Reg2), Irq, cdr.Stat); for (i = 0; i < cdr.ResultC; i++) SysPrintf("%02x ", cdr.Result[i]); SysPrintf("\n"); #endif } +#ifdef __ARM_ARCH_7A__ + #define ssat32_to_16(v) \ + asm("ssat %0,#16,%1" : "=r" (v) : "r" (v)) +#else + #define ssat32_to_16(v) do { \ + if (v < -32768) v = -32768; \ + else if (v > 32767) v = 32767; \ + } while (0) +#endif + +void cdrAttenuate(s16 *buf, int samples, int stereo) +{ + int i, l, r; + int ll = cdr.AttenuatorLeftToLeft; + int lr = cdr.AttenuatorLeftToRight; + int rl = cdr.AttenuatorRightToLeft; + int rr = cdr.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; + ssat32_to_16(l); + ssat32_to_16(r); + buf[i * 2] = l; + buf[i * 2 + 1] = r; + } + } + else { + for (i = 0; i < samples; i++) { + l = buf[i]; + l = l * (ll + rl) >> 7; + //r = r * (rr + lr) >> 7; + ssat32_to_16(l); + //ssat32_to_16(r); + buf[i] = l; + } + } +} + void cdrReadInterrupt() { u8 *buf; @@ -1123,40 +1083,14 @@ void cdrReadInterrupt() { cdr.Channel = cdr.Transfer[4 + 1]; } - if ((cdr.Transfer[4 + 2] & 0x4) && + if((cdr.Transfer[4 + 2] & 0x4) && (cdr.Transfer[4 + 1] == cdr.Channel) && - (cdr.Transfer[4 + 0] == cdr.File)) { + (cdr.Transfer[4 + 0] == cdr.File)) { int ret = xa_decode_sector(&cdr.Xa, cdr.Transfer+4, cdr.FirstSector); - if (!ret) { - // only handle attenuator basic channel switch for now - if (cdr.Xa.stereo) { - int i; - if ((cdr.AttenuatorLeft[0] | cdr.AttenuatorLeft[1]) - && !(cdr.AttenuatorRight[0] | cdr.AttenuatorRight[1])) - { - for (i = 0; i < cdr.Xa.nsamples; i++) - cdr.Xa.pcm[i*2 + 1] = cdr.Xa.pcm[i*2]; - } - else if (!(cdr.AttenuatorLeft[0] | cdr.AttenuatorLeft[1]) - && (cdr.AttenuatorRight[0] | cdr.AttenuatorRight[1])) - { - for (i = 0; i < cdr.Xa.nsamples; i++) - cdr.Xa.pcm[i*2] = cdr.Xa.pcm[i*2 + 1]; - } - } - + cdrAttenuate(cdr.Xa.pcm, cdr.Xa.nsamples, cdr.Xa.stereo); SPU_playADPCMchannel(&cdr.Xa); cdr.FirstSector = 0; - -#if 0 - // Crash Team Racing: music, speech - // - done using cdda decoded buffer (spu irq) - // - don't do here - - // signal ADPCM data ready - setIrq(); -#endif } else cdr.FirstSector = -1; } @@ -1189,8 +1123,6 @@ void cdrReadInterrupt() { // update for CdlGetlocP ReadTrack(cdr.SetSector); - - Check_Shell(0); } /* @@ -1253,7 +1185,7 @@ void cdrWrite1(unsigned char rt) { case 0: break; case 3: - cdr.AttenuatorRight[1] = rt; + cdr.AttenuatorRightToRightT = rt; return; default: return; @@ -1263,7 +1195,7 @@ void cdrWrite1(unsigned char rt) { cdr.OCUP = 0; #ifdef CDR_LOG_CMD_IRQ - SysPrintf("cdrWrite1() Log: CD1 write: %x (%s)", rt, CmdName[rt]); + SysPrintf("CD1 write: %x (%s)", rt, CmdName[rt]); if (cdr.ParamC) { SysPrintf(" Param[%d] = {", cdr.ParamC); for (i = 0; i < cdr.ParamC; i++) @@ -1317,23 +1249,8 @@ void cdrWrite1(unsigned char rt) { // Vib Ribbon: try same track again StopCdda(); -#if 0 - if (!cdr.SetSector[0] & !cdr.SetSector[1] & !cdr.SetSector[2]) { - if (CDR_getTN(cdr.ResultTN) != -1) { - if (cdr.CurTrack > cdr.ResultTN[1]) - cdr.CurTrack = cdr.ResultTN[1]; - if (CDR_getTD((unsigned char)(cdr.CurTrack), cdr.ResultTD) != -1) { - int tmp = cdr.ResultTD[2]; - cdr.ResultTD[2] = cdr.ResultTD[0]; - cdr.ResultTD[0] = tmp; - if (!Config.Cdda) CDR_play(cdr.ResultTD); - } - } - } -#endif // Vib Ribbon - decoded buffer IRQ for CDDA reading // - fixes ribbon timing + music CD mode - //TODO? //CDRDBUF_INT( PSXCLK / 44100 * 0x100 ); cdr.Play = TRUE; @@ -1474,10 +1391,10 @@ void cdrWrite2(unsigned char rt) { setIrq(); return; case 2: - cdr.AttenuatorLeft[0] = rt; + cdr.AttenuatorLeftToLeftT = rt; return; case 3: - cdr.AttenuatorRight[0] = rt; + cdr.AttenuatorRightToLeftT = rt; return; } } @@ -1505,13 +1422,15 @@ void cdrWrite3(unsigned char rt) { cdr.ParamC = 0; return; case 2: - cdr.AttenuatorLeft[1] = rt; + cdr.AttenuatorLeftToRightT = rt; return; case 3: - if (rt == 0x20) - CDR_LOG( "CD-XA Volume: %X %X | %X %X\n", - cdr.AttenuatorLeft[0], cdr.AttenuatorLeft[1], - cdr.AttenuatorRight[0], cdr.AttenuatorRight[1] ); + if (rt & 0x20) { + memcpy(&cdr.AttenuatorLeftToLeft, &cdr.AttenuatorLeftToLeftT, 4); + CDR_LOG_I("CD-XA Volume: %02x %02x | %02x %02x\n", + cdr.AttenuatorLeftToLeft, cdr.AttenuatorLeftToRight, + cdr.AttenuatorRightToLeft, cdr.AttenuatorRightToRight); + } return; } @@ -1556,10 +1475,11 @@ void psxDma3(u32 madr, u32 bcr, u32 chcr) { // - fix boot if( cdsize == 0 ) { - switch (cdr.Mode & 0x30) { - case 0x00: cdsize = 2048; break; - case MODE_SIZE_2328: cdsize = 2328; break; + switch (cdr.Mode & (MODE_SIZE_2340|MODE_SIZE_2328)) { case MODE_SIZE_2340: cdsize = 2340; break; + case MODE_SIZE_2328: cdsize = 2328; break; + default: + case MODE_SIZE_2048: cdsize = 2048; break; } } @@ -1631,13 +1551,16 @@ void cdrReset() { cdr.CurTrack = 1; cdr.File = 1; cdr.Channel = 1; + cdr.Reg2 = 0x1f; + cdr.Stat = NoIntr; + cdr.DriveState = DRIVESTATE_STANDBY; pTransfer = cdr.Transfer; // BIOS player - default values - cdr.AttenuatorLeft[0] = 0x80; - cdr.AttenuatorLeft[1] = 0x00; - cdr.AttenuatorRight[0] = 0x00; - cdr.AttenuatorRight[1] = 0x80; + cdr.AttenuatorLeftToLeft = 0x80; + cdr.AttenuatorLeftToRight = 0x00; + cdr.AttenuatorRightToLeft = 0x00; + cdr.AttenuatorRightToRight = 0x80; getCdInfo(); } @@ -1688,17 +1611,7 @@ int cdrFreeze(void *f, int Mode) { } void LidInterrupt() { - cdr.LidCheck = 0x20; // start checker - getCdInfo(); - StopCdda(); - CDRLID_INT( cdReadTime * 3 ); - - // generate interrupt if none active - open or close - if (cdr.Irq == 0 || cdr.Irq == 0xff) { - cdr.Ctrl |= 0x80; - cdr.Stat = NoIntr; - AddIrqQueue(CdlNop, 0x800); - } + cdrLidSeekInterrupt(); }