Files
pcsx2/pcsx2/CDVD/CDVD.cpp
T

1989 lines
53 KiB
C++

/* Pcsx2 - Pc Ps2 Emulator
* Copyright (C) 2002-2009 Pcsx2 Team
*
* 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 "PrecompiledHeader.h"
#include <ctype.h>
#include <wx/datetime.h>
#include "IopCommon.h"
#include "CDVDiso.h"
#include "CDVD_internal.h"
static cdvdStruct cdvd;
static __forceinline void SetResultSize(u8 size)
{
cdvd.ResultC = size;
cdvd.ResultP = 0;
cdvd.sDataIn&=~0x40;
}
static void CDVDREAD_INT(int eCycle)
{
PSX_INT(IopEvt_CdvdRead, eCycle);
}
static void CDVD_INT(int eCycle)
{
if( eCycle == 0 )
cdvdActionInterrupt();
else
PSX_INT(IopEvt_Cdvd, eCycle);
}
// Sets the cdvd IRQ and the reason for the IRQ, and signals the IOP for a branch
// test (which will cause the exception to be handled).
static void cdvdSetIrq( uint id = (1<<Irq_CommandComplete) )
{
cdvd.PwOff |= id;
iopIntcIrq( 2 );
hwIntcIrq(INTC_SBUS);
psxSetNextBranchDelta( 20 );
}
static int mg_BIToffset(u8 *buffer)
{
int i, ofs = 0x20;
for (i=0; i<*(u16*)&buffer[0x1A]; i++)
ofs+=0x10;
if (*(u16*)&buffer[0x18] & 1) ofs += buffer[ofs];
if ((*(u16*)&buffer[0x18] & 0xF000) == 0) ofs += 8;
return ofs + 0x20;
}
FILE *_cdvdOpenMechaVer() {
char *ptr;
int i;
char file[g_MaxPath];
FILE* fd;
// get the name of the bios file
// use the bios filename to get the name of the mecha ver file
// [TODO] : Upgrade this to use std::string!
strcpy(file, g_Conf.FullpathToBios().ToAscii().data() );
ptr = file;
i = (int)strlen(file);
while (i > 0) { if (ptr[i] == '.') break; i--; }
ptr[i+1] = '\0';
strcat(file, "MEC");
// if file doesnt exist, create empty one
fd = fopen(file, "r+b");
if (fd == NULL) {
Console::Notice("MEC File Not Found , Creating Blank File");
fd = fopen(file, "wb");
if (fd == NULL)
{
Console::Error( "\tMEC File Creation failed!" );
throw Exception::CreateStream( file );
//Msgbox::Alert( "_cdvdOpenMechaVer: Error creating %s", params file);
//exit(1);
}
fputc(0x03, fd);
fputc(0x06, fd);
fputc(0x02, fd);
fputc(0x00, fd);
}
return fd;
}
s32 cdvdGetMechaVer(u8* ver)
{
FILE* fd = _cdvdOpenMechaVer();
if (fd == NULL) return 1;
fseek(fd, 0, SEEK_SET);
fread(ver, 1, 4, fd);
fclose(fd);
return 0;
}
FILE *_cdvdOpenNVM() {
char *ptr;
int i;
char file[g_MaxPath];
FILE* fd;
// get the name of the bios file
// use the bios filename to get the name of the nvm file
// [TODO] : Upgrade this to use std::string!
strcpy( file, g_Conf.FullpathToBios().ToAscii().data() );
ptr = file;
i = (int)strlen(file);
while (i > 0) { if (ptr[i] == '.') break; i--; }
ptr[i+1] = '\0';
strcat(file, "NVM");
// if file doesnt exist, create empty one
fd = fopen(file, "r+b");
if (fd == NULL) {
Console::Notice("NVM File Not Found , Creating Blank File");
fd = fopen(file, "wb");
if (fd == NULL)
{
throw Exception::CreateStream( file );
//Msgbox::Alert("_cdvdOpenNVM: Error creating %s", params file);
//exit(1);
}
for (i=0; i<1024; i++) fputc(0, fd);
}
return fd;
}
//
// the following 'cdvd' functions all return 0 if successful
//
s32 cdvdReadNVM(u8 *dst, int offset, int bytes) {
FILE* fd = _cdvdOpenNVM();
if (fd == NULL) return 1;
fseek(fd, offset, SEEK_SET);
fread(dst, 1, bytes, fd);
fclose(fd);
return 0;
}
s32 cdvdWriteNVM(const u8 *src, int offset, int bytes) {
FILE* fd = _cdvdOpenNVM();
if (fd == NULL) return 1;
fseek(fd, offset, SEEK_SET);
fwrite(src, 1, bytes, fd);
fclose(fd);
return 0;
}
NVMLayout* getNvmLayout(void)
{
NVMLayout* nvmLayout = NULL;
s32 nvmIdx;
for(nvmIdx=0; nvmIdx<NVM_FORMAT_MAX; nvmIdx++)
{
if(nvmlayouts[nvmIdx].biosVer <= BiosVersion)
nvmLayout = &nvmlayouts[nvmIdx];
}
return nvmLayout;
}
s32 getNvmData(u8* buffer, s32 offset, s32 size, s32 fmtOffset)
{
// find the correct bios version
NVMLayout* nvmLayout = getNvmLayout();
if (nvmLayout == NULL) return 1;
// get data from eeprom
return cdvdReadNVM(buffer, *(s32*)(((u8*)nvmLayout)+fmtOffset) + offset, size);
}
s32 setNvmData(const u8* buffer, s32 offset, s32 size, s32 fmtOffset)
{
// find the correct bios version
NVMLayout* nvmLayout = getNvmLayout();
if (nvmLayout == NULL) return 1;
// set data in eeprom
return cdvdWriteNVM(buffer, *(s32*)(((u8*)nvmLayout)+fmtOffset) + offset, size);
}
s32 cdvdReadConsoleID(u8* id)
{
return getNvmData(id, 0, 8, offsetof(NVMLayout, consoleId));
}
s32 cdvdWriteConsoleID(const u8* id)
{
return setNvmData(id, 0, 8, offsetof(NVMLayout, consoleId));
}
s32 cdvdReadILinkID(u8* id)
{
return getNvmData(id, 0, 8, offsetof(NVMLayout, ilinkId));
}
s32 cdvdWriteILinkID(const u8* id)
{
return setNvmData(id, 0, 8, offsetof(NVMLayout, ilinkId));
}
s32 cdvdReadModelNumber(u8* num, s32 part)
{
return getNvmData(num, part, 8, offsetof(NVMLayout, modelNum));
}
s32 cdvdWriteModelNumber(const u8* num, s32 part)
{
return setNvmData(num, part, 8, offsetof(NVMLayout, modelNum));
}
s32 cdvdReadRegionParams(u8* num)
{
return getNvmData(num, 0, 8, offsetof(NVMLayout,regparams));
}
s32 cdvdWriteRegionParams(const u8* num)
{
return setNvmData(num, 0, 8, offsetof(NVMLayout,regparams));
}
s32 cdvdReadMAC(u8* num)
{
return getNvmData(num, 0, 8, offsetof(NVMLayout,mac));
}
s32 cdvdWriteMAC(const u8* num)
{
return setNvmData(num, 0, 8, offsetof(NVMLayout,mac));
}
s32 cdvdReadConfig(u8* config)
{
// make sure its in read mode
if(cdvd.CReadWrite != 0)
{
config[0] = 0x80;
memset(&config[1], 0x00, 15);
return 1;
}
// check if block index is in bounds
else if(cdvd.CBlockIndex >= cdvd.CNumBlocks)
return 1;
else if(
((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))||
((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))||
((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7))
)
{
memzero_ptr<16>(config);
return 0;
}
// get config data
switch (cdvd.COffset)
{
case 0:
return getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config0));
break;
case 2:
return getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config2));
break;
default:
return getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config1));
}
}
s32 cdvdWriteConfig(const u8* config)
{
// make sure its in write mode
if(cdvd.CReadWrite != 1)
return 1;
// check if block index is in bounds
else if(cdvd.CBlockIndex >= cdvd.CNumBlocks)
return 1;
else if(
((cdvd.COffset == 0) && (cdvd.CBlockIndex >= 4))||
((cdvd.COffset == 1) && (cdvd.CBlockIndex >= 2))||
((cdvd.COffset == 2) && (cdvd.CBlockIndex >= 7))
)
return 0;
// get config data
switch (cdvd.COffset)
{
case 0:
return setNvmData(config, (cdvd.CBlockIndex++)*16, 16,offsetof(NVMLayout, config0));
break;
case 2:
return setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config2));
break;
default:
return setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config1));
}
}
void cdvdReadKey(u8 arg0, u16 arg1, u32 arg2, u8* key) {
wxString fname;
char exeName[12];
s32 numbers, letters;
u32 key_0_3;
u8 key_4, key_14;
// get main elf name
GetPS2ElfName(fname);
const wxCharBuffer crap( fname.ToAscii() );
const char* str = crap.data();
sprintf(exeName, "%c%c%c%c%c%c%c%c%c%c%c",str[8],str[9],str[10],str[11],str[12],str[13],str[14],str[15],str[16],str[17],str[18]);
DevCon::Notice("exeName = %s", params &str[8]);
// convert the number characters to a real 32bit number
numbers = ((((exeName[5] - '0'))*10000) +
(((exeName[ 6] - '0'))*1000) +
(((exeName[ 7] - '0'))*100) +
(((exeName[ 9] - '0'))*10) +
(((exeName[10] - '0'))*1) );
// combine the lower 7 bits of each char
// to make the 4 letters fit into a single u32
letters = (s32)((exeName[3]&0x7F)<< 0) |
(s32)((exeName[2]&0x7F)<< 7) |
(s32)((exeName[1]&0x7F)<<14) |
(s32)((exeName[0]&0x7F)<<21);
// calculate magic numbers
key_0_3 = ((numbers & 0x1FC00) >> 10) | ((0x01FFFFFF & letters) << 7); // numbers = 7F letters = FFFFFF80
key_4 = ((numbers & 0x0001F) << 3) | ((0x0E000000 & letters) >> 25); // numbers = F8 letters = 07
key_14 = ((numbers & 0x003E0) >> 2) | 0x04; // numbers = F8 extra = 04 unused = 03
// clear key values
memzero_ptr<16>(key);
// store key values
key[ 0] = (key_0_3&0x000000FF)>> 0;
key[ 1] = (key_0_3&0x0000FF00)>> 8;
key[ 2] = (key_0_3&0x00FF0000)>>16;
key[ 3] = (key_0_3&0xFF000000)>>24;
key[ 4] = key_4;
if(arg2 == 75)
{
key[14] = key_14;
key[15] = 0x05;
}
else if(arg2 == 3075)
{
key[15] = 0x01;
}
else if(arg2 == 4246)
{
// 0x0001F2F707 = sector 0x0001F2F7 dec 0x07
key[ 0] = 0x07;
key[ 1] = 0xF7;
key[ 2] = 0xF2;
key[ 3] = 0x01;
key[ 4] = 0x00;
key[15] = 0x01;
}
else
{
key[15] = 0x01;
}
Console::WriteLn( "CDVD.KEY = %02X,%02X,%02X,%02X,%02X,%02X,%02X", params
cdvd.Key[0],cdvd.Key[1],cdvd.Key[2],cdvd.Key[3],cdvd.Key[4],cdvd.Key[14],cdvd.Key[15] );
// Now's a good time to reload the ELF info...
if( ElfCRC == 0 )
{
ElfCRC = loadElfCRC( str );
ElfApplyPatches();
GSsetGameCRC( ElfCRC, 0 );
}
}
s32 cdvdGetToc(void* toc)
{
s32 ret = CDVDgetTOC(toc);
if (ret == -1) ret = 0x80;
return ret;
}
s32 cdvdReadSubQ(s32 lsn, cdvdSubQ* subq)
{
s32 ret = CDVDreadSubQ(lsn, subq);
if (ret == -1) ret = 0x80;
return ret;
}
s32 cdvdCtrlTrayOpen()
{
s32 ret = CDVDctrlTrayOpen();
if (ret == -1) ret = 0x80;
return ret;
}
s32 cdvdCtrlTrayClose()
{
s32 ret = CDVDctrlTrayClose();
if (ret == -1) ret = 0x80;
return ret;
}
// Modified by (efp) - 16/01/2006
// checks if tray was opened since last call to this func
s32 cdvdGetTrayStatus()
{
s32 ret = CDVDgetTrayStatus();
if (ret == -1)
return(CDVD_TRAY_CLOSE);
else
return(ret);
}
// Note: Is tray status being kept as a var here somewhere?
// cdvdNewDiskCB() can update it's status as well...
// Modified by (efp) - 16/01/2006
static __forceinline void cdvdGetDiskType()
{
// defs 0.9.0
if (CDVDnewDiskCB || (cdvd.Type != CDVD_TYPE_NODISC)) return;
// defs.0.8.1
if (cdvdGetTrayStatus() == CDVD_TRAY_OPEN)
{
cdvd.Type = CDVD_TYPE_NODISC;
return;
}
cdvd.Type = CDVDgetDiskType();
// Is the type listed as a PS2 CD?
if (cdvd.Type == CDVD_TYPE_PS2CD) // && needReset == 1)
{
wxString str;
if (GetPS2ElfName(str) == 1)
{
// Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then.
cdvd.Type = CDVD_TYPE_PSCD;
}
}
}
// check whether disc is single or dual layer
// if its dual layer, check what the disctype is and what sector number
// layer1 starts at
//
// args: gets value for dvd type (0=single layer, 1=ptp, 2=otp)
// gets value for start lsn of layer1
// returns: 1 if on dual layer disc
// 0 if not on dual layer disc
static s32 cdvdReadDvdDualInfo(s32* dualType, u32* layer1Start)
{
u8 toc[2064];
*dualType = 0;
*layer1Start = 0;
// if error getting toc, settle for single layer disc ;)
if(cdvdGetToc(toc))
return 0;
if(toc[14] & 0x60)
{
if(toc[14] & 0x10)
{
// otp dvd
*dualType = 2;
*layer1Start = (toc[25]<<16) + (toc[26]<<8) + (toc[27]) - 0x30000 + 1;
}
else
{
// ptp dvd
*dualType = 1;
*layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1;
}
}
else
{
// single layer dvd
*dualType = 0;
*layer1Start = (toc[21]<<16) + (toc[22]<<8) + (toc[23]) - 0x30000 + 1;
}
return 1;
}
static uint cdvdBlockReadTime( CDVD_MODE_TYPE mode )
{
return (PSXCLK * cdvd.BlockSize) / (((mode==MODE_CDROM) ? PSX_CD_READSPEED : PSX_DVD_READSPEED) * cdvd.Speed);
}
void cdvdReset()
{
memzero_obj(cdvd);
cdvd.Type = CDVD_TYPE_NODISC;
cdvd.Spinning = false;
cdvd.sDataIn = 0x40;
cdvd.Ready = CDVD_READY2;
cdvd.Speed = 4;
cdvd.BlockSize = 2064;
cdvd.Action = cdvdAction_None;
cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
wxDateTime curtime( wxDateTime::GetTimeNow() );
cdvd.RTC.second = (u8)curtime.GetSecond();
cdvd.RTC.minute = (u8)curtime.GetMinute();
cdvd.RTC.hour = (u8)(curtime.GetHour()+1) % 24;
cdvd.RTC.day = (u8)curtime.GetDay();
cdvd.RTC.month = (u8)curtime.GetMonth();
cdvd.RTC.year = (u8)(curtime.GetYear() - 2000);
}
struct Freeze_v10Compat
{
u8 Action;
u32 SeekToSector;
u32 ReadTime;
bool Spinning;
};
void SaveState::cdvdFreeze()
{
FreezeTag( "cdvd" );
Freeze( cdvd );
if (IsLoading())
{
// Make sure the Cdvd plugin has the expected track loaded into the buffer.
// If cdvd.Readed is cleared it means we need to load the SeekToSector (ie, a
// seek is in progress!)
if( cdvd.Reading )
cdvd.RErr = CDVDreadTrack( cdvd.Readed ? cdvd.Sector : cdvd.SeekToSector, cdvd.ReadMode);
}
}
// Modified by (efp) - 16/01/2006
void cdvdNewDiskCB()
{
cdvd.Type = CDVDgetDiskType();
wxString str;
int result = GetPS2ElfName(str);
if (cdvd.Type == CDVD_TYPE_PS2CD)
{
// Does the SYSTEM.CNF file only say "BOOT="? PS1 CD then.
if(result == 1) cdvd.Type = CDVD_TYPE_PSCD;
}
// Now's a good time to reload the ELF info...
if( ElfCRC == 0 )
{
ElfCRC = loadElfCRC( str.ToAscii().data() );
ElfApplyPatches();
GSsetGameCRC( ElfCRC, 0 );
}
}
void mechaDecryptBytes( u32 madr, int size )
{
int i;
int shiftAmount = (cdvd.decSet>>4) & 7;
int doXor = (cdvd.decSet) & 1;
int doShift = (cdvd.decSet) & 2;
u8* curval = iopPhysMem( madr );
for( i=0; i<size; ++i, ++curval )
{
if( doXor ) *curval ^= cdvd.Key[4];
if( doShift ) *curval = (*curval >> shiftAmount) | (*curval << (8-shiftAmount) );
}
}
int cdvdReadSector() {
s32 bcr;
CDR_LOG("SECTOR %d (BCR %x;%x)", cdvd.Sector, HW_DMA3_BCR_H16, HW_DMA3_BCR_L16);
bcr = (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4;
if (bcr < cdvd.BlockSize) {
CDR_LOG( "READBLOCK: bcr < cdvd.BlockSize; %x < %x", bcr, cdvd.BlockSize );
if (HW_DMA3_CHCR & 0x01000000) {
HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3);
}
return -1;
}
// DMAs use physical addresses (air)
u8* mdest = iopPhysMem( HW_DMA3_MADR );
// if raw dvd sector 'fill in the blanks'
if (cdvd.BlockSize == 2064)
{
// get info on dvd type and layer1 start
u32 layer1Start;
s32 dualType;
s32 layerNum;
u32 lsn = cdvd.Sector;
cdvdReadDvdDualInfo(&dualType, &layer1Start);
if((dualType == 1) && (lsn >= layer1Start))
{
// dual layer ptp disc
layerNum = 1;
lsn = lsn-layer1Start + 0x30000;
}
else if((dualType == 2) && (lsn >= layer1Start))
{
// dual layer otp disc
layerNum = 1;
lsn = ~(layer1Start+0x30000 - 1);
}
else
{ // Assumed the other dualType is 0.
// single layer disc
// or on first layer of dual layer disc
layerNum = 0;
lsn += 0x30000;
}
mdest[0] = 0x20 | layerNum;
mdest[1] = (u8)(lsn >> 16);
mdest[2] = (u8)(lsn >> 8);
mdest[3] = (u8)(lsn );
// sector IED (not calculated at present)
mdest[4] = 0;
mdest[5] = 0;
// sector CPR_MAI (not calculated at present)
mdest[6] = 0;
mdest[7] = 0;
mdest[8] = 0;
mdest[9] = 0;
mdest[10] = 0;
mdest[11] = 0;
// normal 2048 bytes of sector data
memcpy_fast( &mdest[12], cdr.pTransfer, 2048);
// 4 bytes of edc (not calculated at present)
mdest[2060] = 0;
mdest[2061] = 0;
mdest[2062] = 0;
mdest[2063] = 0;
}
else
{
memcpy_fast( mdest, cdr.pTransfer, cdvd.BlockSize);
}
// decrypt sector's bytes
if( cdvd.decSet ) mechaDecryptBytes( HW_DMA3_MADR, cdvd.BlockSize );
// Added a clear after memory write .. never seemed to be necessary before but *should*
// be more correct. (air)
psxCpu->Clear( HW_DMA3_MADR, cdvd.BlockSize/4 );
// Console::WriteLn("sector %x;%x;%x", params PSXMu8(madr+0), PSXMu8(madr+1), PSXMu8(madr+2));
HW_DMA3_BCR_H16 -= (cdvd.BlockSize / (HW_DMA3_BCR_L16*4));
HW_DMA3_MADR += cdvd.BlockSize;
return 0;
}
// inlined due to being referenced in only one place.
__forceinline void cdvdActionInterrupt()
{
switch( cdvd.Action )
{
case cdvdAction_Seek:
case cdvdAction_Standby:
cdvd.Spinning = true;
cdvd.Ready = CDVD_READY1;
cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_SEEK_COMPLETE;
break;
case cdvdAction_Stop:
cdvd.Spinning = false;
cdvd.Ready = CDVD_READY1;
cdvd.Sector = 0;
cdvd.Status = CDVD_STATUS_NONE;
break;
case cdvdAction_Break:
// Make sure the cdvd action state is pretty well cleared:
cdvd.Reading = 0;
cdvd.Readed = 0;
cdvd.Ready = CDVD_READY2; // should be CDVD_READY1 or something else?
cdvd.Status = CDVD_STATUS_NONE;
cdvd.RErr = 0;
cdvd.nCommand = 0;
break;
}
cdvd.Action = cdvdAction_None;
cdvd.PwOff |= 1<<Irq_CommandComplete;
psxHu32(0x1070)|= 0x4;
hwIntcIrq(INTC_SBUS);
}
// inlined due to being referenced in only one place.
__forceinline void cdvdReadInterrupt()
{
//Console::WriteLn("cdvdReadInterrupt %x %x %x %x %x", params cpuRegs.interrupt, cdvd.Readed, cdvd.Reading, cdvd.nSectors, (HW_DMA3_BCR_H16 * HW_DMA3_BCR_L16) *4);
cdvd.Ready = CDVD_NOTREADY;
if (!cdvd.Readed)
{
// Seeking finished. Process the track we requested before, and
// then schedule another CDVD read int for when the block read finishes.
// NOTE: The first CD track was read when the seek was initiated, so no need
// to call CDVDReadTrack here.
cdvd.Spinning = true;
cdvd.RetryCntP = 0;
cdvd.Reading = 1;
cdvd.Readed = 1;
cdvd.Status = CDVD_STATUS_SEEK_COMPLETE;
cdvd.Sector = cdvd.SeekToSector;
CDR_LOG( "Cdvd Seek Complete > Scheduling block read interrupt at iopcycle=%8.8x.",
psxRegs.cycle + cdvd.ReadTime );
CDVDREAD_INT(cdvd.ReadTime);
return;
}
else
{
if (cdvd.RErr == 0)
cdr.pTransfer = CDVDgetBuffer();
else
cdr.pTransfer = NULL;
if (cdr.pTransfer == NULL)
{
cdvd.RetryCntP++;
Console::Error("CDVD READ ERROR, sector=%d", params cdvd.Sector);
if (cdvd.RetryCntP <= cdvd.RetryCnt)
{
cdvd.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode);
CDVDREAD_INT(cdvd.ReadTime);
return;
}
}
cdvd.Reading = false;
}
if (cdvdReadSector() == -1)
{
assert((int)cdvd.ReadTime > 0 );
CDVDREAD_INT(cdvd.ReadTime);
return;
}
cdvd.Sector++;
if (--cdvd.nSectors <= 0)
{
cdvd.PwOff |= 1<<Irq_CommandComplete;
psxHu32(0x1070)|= 0x4;
hwIntcIrq(INTC_SBUS);
HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3);
cdvd.Ready = CDVD_READY2;
// All done! :D
return;
}
cdvd.RetryCntP = 0;
cdvd.Reading = 1;
cdr.RErr = CDVDreadTrack(cdvd.Sector, cdvd.ReadMode);
CDVDREAD_INT(cdvd.ReadTime);
return;
}
// Returns the number of IOP cycles until the event completes.
static uint cdvdStartSeek( uint newsector, CDVD_MODE_TYPE mode )
{
cdvd.SeekToSector = newsector;
uint delta = abs( (s32)(cdvd.SeekToSector - cdvd.Sector) );
uint seektime;
cdvd.Ready = CDVD_NOTREADY;
cdvd.Reading = 0;
cdvd.Readed = 0;
cdvd.Status = CDVD_STATUS_NONE;
if( !cdvd.Spinning )
{
CDR_LOG( "CdSpinUp > Simulating CdRom Spinup Time, and seek to sector %d", cdvd.SeekToSector );
seektime = PSXCLK / 3; // 333ms delay
cdvd.Spinning = true;
}
else if( (tbl_ContigiousSeekDelta[mode] == 0) || (delta >= tbl_ContigiousSeekDelta[mode]) )
{
// Select either Full or Fast seek depending on delta:
if( delta >= tbl_FastSeekDelta[mode] )
{
// Full Seek
CDR_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d [FULL]", cdvd.SeekToSector, cdvd.Sector, delta );
seektime = Cdvd_FullSeek_Cycles;
}
else
{
CDR_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d [FAST]", cdvd.SeekToSector, cdvd.Sector, delta );
seektime = Cdvd_FastSeek_Cycles;
}
}
else
{
CDR_LOG( "CdSeek Begin > Contiguous block without seek - delta=%d sectors", delta );
// seektime is the time it takes to read to the destination block:
seektime = delta * cdvd.ReadTime;
if( delta == 0 )
{
cdvd.Status = CDVD_STATUS_SEEK_COMPLETE;
cdvd.Readed = 1; // Note: 1, not 0, as implied by the next comment. Need to look into this. --arcum42
cdvd.RetryCntP = 0;
// setting Readed to 0 skips the seek logic, which means the next call to
// cdvdReadInterrupt will load a block. So make sure it's properly scheduled
// based on sector read speeds:
seektime = cdvd.ReadTime;
}
}
return seektime;
}
u8 monthmap[13] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
void cdvdVsync() {
cdvd.RTCcount++;
if (cdvd.RTCcount < ((Config.PsxType & 1) ? 50 : 60)) return;
cdvd.RTCcount = 0;
cdvd.RTC.second++;
if (cdvd.RTC.second < 60) return;
cdvd.RTC.second = 0;
cdvd.RTC.minute++;
if (cdvd.RTC.minute < 60) return;
cdvd.RTC.minute = 0;
cdvd.RTC.hour++;
if (cdvd.RTC.hour < 24) return;
cdvd.RTC.hour = 0;
cdvd.RTC.day++;
if (cdvd.RTC.day <= monthmap[cdvd.RTC.month-1]) return;
cdvd.RTC.day = 1;
cdvd.RTC.month++;
if (cdvd.RTC.month <= 12) return;
cdvd.RTC.month = 1;
cdvd.RTC.year++;
if (cdvd.RTC.year < 100) return;
cdvd.RTC.year = 0;
}
static __forceinline u8 cdvdRead18(void) // SDATAOUT
{
u8 ret = 0;
if (((cdvd.sDataIn & 0x40) == 0) && (cdvd.ResultP < cdvd.ResultC))
{
cdvd.ResultP++;
if (cdvd.ResultP >= cdvd.ResultC) cdvd.sDataIn|= 0x40;
ret = cdvd.Result[cdvd.ResultP-1];
}
CDR_LOG("cdvdRead18(SDataOut) %x (ResultC=%d, ResultP=%d)", ret, cdvd.ResultC, cdvd.ResultP);
return ret;
}
u8 cdvdRead(u8 key)
{
switch (key)
{
case 0x04: // NCOMMAND
CDR_LOG("cdvdRead04(NCMD) %x", cdvd.nCommand);
return cdvd.nCommand;
break;
case 0x05: // N-READY
CDR_LOG("cdvdRead05(NReady) %x", cdvd.Ready);
return cdvd.Ready;
break;
case 0x06: // ERROR
CDR_LOG("cdvdRead06(Error) %x", cdvd.Error);
return cdvd.Error;
break;
case 0x07: // BREAK
CDR_LOG("cdvdRead07(Break) %x", 0);
return 0;
break;
case 0x08: // STATUS
CDR_LOG("cdvdRead0A(Status) %x", cdvd.Status);
return cdvd.Status;
break;
case 0x0A: // STATUS
CDR_LOG("cdvdRead0A(Status) %x", cdvd.Status);
return cdvd.Status;
break;
case 0x0B: // TRAY-STATE (if tray has been opened)
{
u8 tray = cdvdGetTrayStatus();
CDR_LOG("cdvdRead0B(Tray) %x", tray);
return tray;
break;
}
case 0x0C: // CRT MINUTE
CDR_LOG("cdvdRead0C(Min) %x", itob((u8)(cdvd.Sector/(60*75))));
return itob((u8)(cdvd.Sector/(60*75)));
break;
case 0x0D: // CRT SECOND
CDR_LOG("cdvdRead0D(Sec) %x", itob((u8)((cdvd.Sector/75)%60)+2));
return itob((u8)((cdvd.Sector/75)%60)+2);
break;
case 0x0E: // CRT FRAME
CDR_LOG("cdvdRead0E(Frame) %x", itob((u8)(cdvd.Sector%75)));
return itob((u8)(cdvd.Sector%75));
break;
case 0x0F: // TYPE
CDR_LOG("cdvdRead0F(Disc Type) %x", cdvd.Type);
cdvdGetDiskType();
return cdvd.Type;
break;
case 0x13: // UNKNOWN
CDR_LOG("cdvdRead13(Unknown) %x", 4);
return 4;
break;
case 0x15: // RSV
CDR_LOG("cdvdRead15(RSV)");
return 0x01; // | 0x80 for ATAPI mode
break;
case 0x16: // SCOMMAND
CDR_LOG("cdvdRead16(SCMD) %x", cdvd.sCommand);
return cdvd.sCommand;
break;
case 0x17: // SREADY
CDR_LOG("cdvdRead17(SReady) %x", cdvd.sDataIn);
return cdvd.sDataIn;
break;
case 0x18:
return cdvdRead18();
break;
case 0x20:
case 0x21:
case 0x22:
case 0x23:
case 0x24:
{
int temp = key - 0x20;
CDR_LOG("cdvdRead%d(Key%d) %x", key, temp, cdvd.Key[temp]);
return cdvd.Key[temp];
break;
}
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
{
int temp = key - 0x23;
CDR_LOG("cdvdRead%d(Key%d) %x", key, temp, cdvd.Key[temp]);
return cdvd.Key[temp];
break;
}
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
{
int temp = key - 0x26;
CDR_LOG("cdvdRead%d(Key%d) %x", key, temp, cdvd.Key[temp]);
return cdvd.Key[temp];
break;
}
case 0x38: // valid parts of key data (first and last are valid)
CDR_LOG("cdvdRead38(KeysValid) %x", cdvd.Key[15]);
return cdvd.Key[15];
break;
case 0x39: // KEY-XOR
CDR_LOG("cdvdRead39(KeyXor) %x", cdvd.KeyXor);
return cdvd.KeyXor;
break;
case 0x3A: // DEC_SET
CDR_LOG("cdvdRead3A(DecSet) %x", cdvd.decSet);
Console::WriteLn("DecSet Read: %02X", params cdvd.decSet);
return cdvd.decSet;
break;
default:
// note: notify the console since this is a potentially serious emulation problem:
PSXHW_LOG("*Unknown 8bit read at address 0x1f4020%x", key);
Console::Error( "IOP Unknown 8bit read from addr 0x1f4020%x", params key );
return 0;
break;
}
}
static void cdvdWrite04(u8 rt) { // NCOMMAND
CDR_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)", nCmdName[rt], rt, cdvd.ParamP);
cdvd.nCommand = rt;
cdvd.Status = CDVD_STATUS_NONE;
cdvd.PwOff = Irq_None; // good or bad?
switch (rt) {
case N_CD_SYNC: // CdSync
case N_CD_NOP: // CdNop_
cdvdSetIrq();
break;
case N_CD_STANDBY: // CdStandby
// Seek to sector zero. The cdvdStartSeek function will simulate
// spinup times if needed.
DevCon::Notice( "CdStandby : %d", params rt );
cdvd.Action = cdvdAction_Standby;
cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
CDVD_INT( cdvdStartSeek( 0, MODE_DVDROM ) );
break;
case N_CD_STOP: // CdStop
DevCon::Notice( "CdStop : %d", params rt );
cdvd.Action = cdvdAction_Stop;
CDVD_INT( PSXCLK / 6 ); // 166ms delay?
break;
// from an emulation point of view there is not much need to do anything for this one
case N_CD_PAUSE: // CdPause
cdvdSetIrq();
break;
case N_CD_SEEK: // CdSeek
cdvd.Action = cdvdAction_Seek;
cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
CDVD_INT( cdvdStartSeek( *(uint*)(cdvd.Param+0), MODE_DVDROM ) );
break;
case N_CD_READ: // CdRead
cdvd.SeekToSector = *(uint*)(cdvd.Param+0);
cdvd.nSectors = *(int*)(cdvd.Param+4);
cdvd.RetryCnt = (cdvd.Param[8] == 0) ? 0x100 : cdvd.Param[8];
cdvd.SpindlCtrl = cdvd.Param[9];
cdvd.Speed = 24;
switch (cdvd.Param[10]) {
case 2: cdvd.ReadMode = CDVD_MODE_2340; cdvd.BlockSize = 2340; break;
case 1: cdvd.ReadMode = CDVD_MODE_2328; cdvd.BlockSize = 2328; break;
case 0:
default: cdvd.ReadMode = CDVD_MODE_2048; cdvd.BlockSize = 2048; break;
}
CDR_LOG( "CdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)",
cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074));
if( Config.cdvdPrint )
Console::WriteLn("CdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
params cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed);
cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM );
CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector,MODE_CDROM ) );
// Read-ahead by telling the plugin about the track now.
// This helps improve performance on actual from-cd emulation
// (ie, not using the hard drive)
cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode );
// Set the reading block flag. If a seek is pending then Readed will
// take priority in the handler anyway. If the read is contiguous then
// this'll skip the seek delay.
cdvd.Reading = 1;
break;
case N_CD_READ_CDDA: // CdReadCDDA
case N_CD_READ_XCDDA: // CdReadXCDDA
cdvd.SeekToSector = *(int*)(cdvd.Param+0);
cdvd.nSectors = *(int*)(cdvd.Param+4);
if (cdvd.Param[8] == 0)
cdvd.RetryCnt = 0x100;
else
cdvd.RetryCnt = cdvd.Param[8];
cdvd.SpindlCtrl = cdvd.Param[9];
switch (cdvd.Param[9]) {
case 0x01: cdvd.Speed = 1; break;
case 0x02: cdvd.Speed = 2; break;
case 0x03: cdvd.Speed = 4; break;
case 0x04: cdvd.Speed = 12; break;
default: cdvd.Speed = 24; break;
}
switch (cdvd.Param[10]) {
case 1: cdvd.ReadMode = CDVD_MODE_2368; cdvd.BlockSize = 2368; break;
case 2:
case 0: cdvd.ReadMode = CDVD_MODE_2352; cdvd.BlockSize = 2352; break;
}
CDR_LOG( "CdReadCDDA > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%xx(%x), ReadMode=%x(%x) (1074=%x)",
cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074));
if( Config.cdvdPrint )
Console::WriteLn("CdAudioRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
params cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed);
cdvd.ReadTime = cdvdBlockReadTime( MODE_CDROM );
CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector, MODE_CDROM ) );
// Read-ahead by telling the plugin about the track now.
// This helps improve performance on actual from-cd emulation
// (ie, not using the hard drive)
cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode );
// Set the reading block flag. If a seek is pending then Readed will
// take priority in the handler anyway. If the read is contiguous then
// this'll skip the seek delay.
cdvd.Reading = 1;
break;
case N_DVD_READ: // DvdRead
cdvd.SeekToSector = *(int*)(cdvd.Param+0);
cdvd.nSectors = *(int*)(cdvd.Param+4);
if (cdvd.Param[8] == 0)
cdvd.RetryCnt = 0x100;
else
cdvd.RetryCnt = cdvd.Param[8];
cdvd.SpindlCtrl = cdvd.Param[9];
cdvd.Speed = 4;
cdvd.ReadMode = CDVD_MODE_2048;
cdvd.BlockSize = 2064; // Why oh why was it 2064
CDR_LOG( "DvdRead > startSector=%d, nSectors=%d, RetryCnt=%x, Speed=%x(%x), ReadMode=%x(%x) (1074=%x)",
cdvd.Sector, cdvd.nSectors, cdvd.RetryCnt, cdvd.Speed, cdvd.Param[9], cdvd.ReadMode, cdvd.Param[10], psxHu32(0x1074));
if( Config.cdvdPrint )
Console::WriteLn("DvdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
params cdvd.Sector, cdvd.nSectors,cdvd.BlockSize,cdvd.Speed);
cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
CDVDREAD_INT( cdvdStartSeek( cdvd.SeekToSector, MODE_DVDROM ) );
// Read-ahead by telling the plugin about the track now.
// This helps improve performance on actual from-cd emulation
// (ie, not using the hard drive)
cdvd.RErr = CDVDreadTrack( cdvd.SeekToSector, cdvd.ReadMode );
// Set the reading block flag. If a seek is pending then Readed will
// take priority in the handler anyway. If the read is contiguous then
// this'll skip the seek delay.
cdvd.Reading = 1;
break;
case N_CD_GET_TOC: // CdGetToc & cdvdman_call19
//Param[0] is 0 for CdGetToc and any value for cdvdman_call19
//the code below handles only CdGetToc!
//if(cdvd.Param[0]==0x01)
//{
DevCon::WriteLn("CDGetToc Param[0]=%d, Param[1]=%d", params cdvd.Param[0],cdvd.Param[1]);
//}
cdvdGetToc( iopPhysMem( HW_DMA3_MADR ) );
cdvdSetIrq( (1<<Irq_CommandComplete) ); //| (1<<Irq_DataReady) );
HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3);
break;
case N_CD_READ_KEY: // CdReadKey
{
u8 arg0 = cdvd.Param[0];
u16 arg1 = cdvd.Param[1] | (cdvd.Param[2]<<8);
u32 arg2 = cdvd.Param[3] | (cdvd.Param[4]<<8) | (cdvd.Param[5]<<16) | (cdvd.Param[6]<<24);
DevCon::WriteLn("cdvdReadKey(%d, %d, %d)", params arg0, arg1, arg2);
cdvdReadKey(arg0, arg1, arg2, cdvd.Key);
cdvd.KeyXor = 0x00;
cdvdSetIrq();
}
break;
case N_CD_CHG_SPDL_CTRL: // CdChgSpdlCtrl
Console::Notice("sceCdChgSpdlCtrl(%d)", params cdvd.Param[0]);
cdvdSetIrq();
break;
default:
Console::Notice("NCMD Unknown %x", params rt);
cdvdSetIrq();
break;
}
cdvd.ParamP = 0;
cdvd.ParamC = 0;
}
static __forceinline void cdvdWrite05(u8 rt) { // NDATAIN
CDR_LOG("cdvdWrite05(NDataIn) %x", rt);
if (cdvd.ParamP < 32) {
cdvd.Param[cdvd.ParamP++] = rt;
cdvd.ParamC++;
}
}
static __forceinline void cdvdWrite06(u8 rt) { // HOWTO
CDR_LOG("cdvdWrite06(HowTo) %x", rt);
cdvd.HowTo = rt;
}
static __forceinline void cdvdWrite07(u8 rt) // BREAK
{
CDR_LOG("cdvdWrite07(Break) %x", rt);
// If we're already in a Ready state or already Breaking, then do nothing:
if ((cdvd.Ready != CDVD_NOTREADY) || (cdvd.Action == cdvdAction_Break)) return;
DbgCon::Notice("*PCSX2*: CDVD BREAK %x", params rt);
// Aborts any one of several CD commands:
// Pause, Seek, Read, Status, Standby, and Stop
psxRegs.interrupt &= ~( (1<<IopEvt_Cdvd) | (1<<IopEvt_CdvdRead) );
cdvd.Action = cdvdAction_Break;
CDVD_INT( 64 );
// Clear the cdvd status:
cdvd.Readed = 0;
cdvd.Reading = 0;
cdvd.Status = CDVD_STATUS_NONE;
//cdvd.nCommand = 0;
}
static __forceinline void cdvdWrite08(u8 rt) { // INTR_STAT
CDR_LOG("cdvdWrite08(IntrReason) = ACK(%x)", rt);
cdvd.PwOff &= ~rt;
}
static __forceinline void cdvdWrite0A(u8 rt) { // STATUS
CDR_LOG("cdvdWrite0A(Status) %x", rt);
}
static __forceinline void cdvdWrite0F(u8 rt) { // TYPE
CDR_LOG("cdvdWrite0F(Type) %x", rt);
DevCon::WriteLn("*PCSX2*: CDVD TYPE %x", params rt);
}
static __forceinline void cdvdWrite14(u8 rt) { // PS1 MODE??
u32 cycle = psxRegs.cycle;
if (rt == 0xFE)
Console::Notice("*PCSX2*: go PS1 mode DISC SPEED = FAST");
else
Console::Notice("*PCSX2*: go PS1 mode DISC SPEED = %dX", params rt);
psxReset();
psxHu32(0x1f801450) = 0x8;
psxHu32(0x1f801078) = 1;
psxRegs.cycle = cycle;
}
static __forceinline void fail_pol_cal()
{
Console::Error("[MG] ERROR - Make sure the file is already decrypted!!!");
cdvd.Result[0] = 0x80;
}
static void cdvdWrite16(u8 rt) // SCOMMAND
{
// cdvdTN diskInfo;
// cdvdTD trackInfo;
// int i, lbn, type, min, sec, frm, address;
int address;
u8 tmp;
CDR_LOG("cdvdWrite16: SCMD %s (%x) (ParamP = %x)", sCmdName[rt], rt, cdvd.ParamP);
cdvd.sCommand = rt;
switch (rt) {
// case 0x01: // GetDiscType - from cdvdman (0:1)
// SetResultSize(1);
// cdvd.Result[0] = 0;
// break;
case 0x02: // CdReadSubQ (0:11)
SetResultSize(11);
cdvd.Result[0] = cdvdReadSubQ(cdvd.Sector, (cdvdSubQ*)&cdvd.Result[1]);
break;
case 0x03: // Mecacon-command
switch (cdvd.Param[0])
{
case 0x00: // get mecha version (1:4)
SetResultSize(4);
cdvdGetMechaVer(&cdvd.Result[0]);
break;
case 0x44: // write console ID (9:1)
SetResultSize(1);
cdvd.Result[0] = cdvdWriteConsoleID(&cdvd.Param[1]);
break;
case 0x45: // read console ID (1:9)
SetResultSize(9);
cdvd.Result[0] = cdvdReadConsoleID(&cdvd.Result[1]);
break;
case 0xFD: // _sceCdReadRenewalDate (1:6) BCD
SetResultSize(6);
cdvd.Result[0] = 0;
cdvd.Result[1] = 0x04;//year
cdvd.Result[2] = 0x12;//month
cdvd.Result[3] = 0x10;//day
cdvd.Result[4] = 0x01;//hour
cdvd.Result[5] = 0x30;//min
break;
default:
SetResultSize(1);
cdvd.Result[0] = 0x80;
Console::WriteLn("*Unknown Mecacon Command param[0]=%02X", params cdvd.Param[0]);
break;
}
break;
case 0x05: // CdTrayReqState (0:1) - resets the tray open detection
SetResultSize(1);
cdvd.Result[0] = 0;
break;
case 0x06: // CdTrayCtrl (1:1)
SetResultSize(1);
if(cdvd.Param[0] == 0)
cdvd.Result[0] = cdvdCtrlTrayOpen();
else
cdvd.Result[0] = cdvdCtrlTrayClose();
break;
case 0x08: // CdReadRTC (0:8)
SetResultSize(8);
cdvd.Result[0] = 0;
cdvd.Result[1] = itob(cdvd.RTC.second); //Seconds
cdvd.Result[2] = itob(cdvd.RTC.minute); //Minutes
cdvd.Result[3] = itob((cdvd.RTC.hour+8) %24); //Hours
cdvd.Result[4] = 0; //Nothing
cdvd.Result[5] = itob(cdvd.RTC.day); //Day
if(cdvd.Result[3] <= 7) cdvd.Result[5] += 1;
cdvd.Result[6] = itob(cdvd.RTC.month)+0x80; //Month
cdvd.Result[7] = itob(cdvd.RTC.year); //Year
/*Console::WriteLn("RTC Read Sec %x Min %x Hr %x Day %x Month %x Year %x", params cdvd.Result[1], cdvd.Result[2],
cdvd.Result[3], cdvd.Result[5], cdvd.Result[6], cdvd.Result[7]);
Console::WriteLn("RTC Read Real Sec %d Min %d Hr %d Day %d Month %d Year %d", params cdvd.RTC.second, cdvd.RTC.minute,
cdvd.RTC.hour, cdvd.RTC.day, cdvd.RTC.month, cdvd.RTC.year);*/
break;
case 0x09: // sceCdWriteRTC (7:1)
SetResultSize(1);
cdvd.Result[0] = 0;
cdvd.RTC.pad = 0;
cdvd.RTC.second = btoi(cdvd.Param[cdvd.ParamP-7]);
cdvd.RTC.minute = btoi(cdvd.Param[cdvd.ParamP-6]) % 60;
cdvd.RTC.hour = (btoi(cdvd.Param[cdvd.ParamP-5])+16) % 24;
cdvd.RTC.day = btoi(cdvd.Param[cdvd.ParamP-3]);
if(cdvd.Param[cdvd.ParamP-5] <= 7) cdvd.RTC.day -= 1;
cdvd.RTC.month = btoi(cdvd.Param[cdvd.ParamP-2]-0x80);
cdvd.RTC.year = btoi(cdvd.Param[cdvd.ParamP-1]);
/*Console::WriteLn("RTC write incomming Sec %x Min %x Hr %x Day %x Month %x Year %x", params cdvd.Param[cdvd.ParamP-7], cdvd.Param[cdvd.ParamP-6],
cdvd.Param[cdvd.ParamP-5], cdvd.Param[cdvd.ParamP-3], cdvd.Param[cdvd.ParamP-2], cdvd.Param[cdvd.ParamP-1]);
Console::WriteLn("RTC Write Sec %d Min %d Hr %d Day %d Month %d Year %d", params cdvd.RTC.second, cdvd.RTC.minute,
cdvd.RTC.hour, cdvd.RTC.day, cdvd.RTC.month, cdvd.RTC.year);*/
//memcpy_fast((u8*)&cdvd.RTC, cdvd.Param, 7);
break;
case 0x0A: // sceCdReadNVM (2:3)
address = (cdvd.Param[0]<<8) | cdvd.Param[1];
if (address < 512)
{
SetResultSize(3);
cdvd.Result[0] = cdvdReadNVM(&cdvd.Result[1], address*2, 2);
// swap bytes around
tmp = cdvd.Result[1];
cdvd.Result[1] = cdvd.Result[2];
cdvd.Result[2] = tmp;
}
else
{
SetResultSize(1);
cdvd.Result[0] = 0xff;
}
break;
case 0x0B: // sceCdWriteNVM (4:1)
SetResultSize(1);
address = (cdvd.Param[0]<<8) | cdvd.Param[1];
if (address < 512)
{
// swap bytes around
tmp = cdvd.Param[2];
cdvd.Param[2] = cdvd.Param[3];
cdvd.Param[3] = tmp;
cdvd.Result[0] = cdvdWriteNVM(&cdvd.Param[2], address*2, 2);
}
else
{
cdvd.Result[0] = 0xff;
}
break;
// case 0x0C: // sceCdSetHDMode (1:1)
// break;
case 0x0F: // sceCdPowerOff (0:1)- Call74 from Xcdvdman
SetResultSize(1);
cdvd.Result[0] = 0;
break;
case 0x12: // sceCdReadILinkId (0:9)
SetResultSize(9);
cdvd.Result[0] = cdvdReadILinkID(&cdvd.Result[1]);
break;
case 0x13: // sceCdWriteILinkID (8:1)
SetResultSize(1);
cdvd.Result[0] = cdvdWriteILinkID(&cdvd.Param[1]);
break;
case 0x14: // CdCtrlAudioDigitalOut (1:1)
//parameter can be 2, 0, ...
SetResultSize(1);
cdvd.Result[0] = 0; //8 is a flag; not used
break;
case 0x15: // sceCdForbidDVDP (0:1)
//Console::WriteLn("sceCdForbidDVDP");
SetResultSize(1);
cdvd.Result[0] = 5;
break;
case 0x16: // AutoAdjustCtrl - from cdvdman (1:1)
SetResultSize(1);
cdvd.Result[0] = 0;
break;
case 0x17: // CdReadModelNumber (1:9) - from xcdvdman
SetResultSize(9);
cdvd.Result[0] = cdvdReadModelNumber(&cdvd.Result[1], cdvd.Param[0]);
break;
case 0x18: // CdWriteModelNumber (9:1) - from xcdvdman
SetResultSize(1);
cdvd.Result[0] = cdvdWriteModelNumber(&cdvd.Param[1], cdvd.Param[0]);
break;
// case 0x19: // sceCdForbidRead (0:1) - from xcdvdman
// break;
case 0x1A: // sceCdBootCertify (4:1)//(4:16 in psx?)
SetResultSize(1);//on input there are 4 bytes: 1;?10;J;C for 18000; 1;60;E;C for 39002 from ROMVER
cdvd.Result[0] = 1;//i guess that means okay
break;
case 0x1B: // sceCdCancelPOffRdy (0:1) - Call73 from Xcdvdman (1:1)
SetResultSize(1);
cdvd.Result[0] = 0;
break;
case 0x1C: // sceCdBlueLEDCtl (1:1) - Call72 from Xcdvdman
SetResultSize(1);
cdvd.Result[0] = 0;
break;
// case 0x1D: // cdvdman_call116 (0:5) - In V10 Bios
// break;
case 0x1E: // sceRemote2Read (0:5) - // 00 14 AA BB CC -> remote key code
SetResultSize(5);
cdvd.Result[0] = 0x00;
cdvd.Result[1] = 0x14;
cdvd.Result[2] = 0x00;
cdvd.Result[3] = 0x00;
cdvd.Result[4] = 0x00;
break;
// case 0x1F: // sceRemote2_7 (2:1) - cdvdman_call117
// break;
case 0x20: // sceRemote2_6 (0:3) // 00 01 00
SetResultSize(3);
cdvd.Result[0] = 0x00;
cdvd.Result[1] = 0x01;
cdvd.Result[2] = 0x00;
break;
// case 0x21: // sceCdWriteWakeUpTime (8:1)
// break;
case 0x22: // sceCdReadWakeUpTime (0:10)
SetResultSize(10);
cdvd.Result[0] = 0;
cdvd.Result[1] = 0;
cdvd.Result[2] = 0;
cdvd.Result[3] = 0;
cdvd.Result[4] = 0;
cdvd.Result[5] = 0;
cdvd.Result[6] = 0;
cdvd.Result[7] = 0;
cdvd.Result[8] = 0;
cdvd.Result[9] = 0;
break;
case 0x24: // sceCdRCBypassCtrl (1:1) - In V10 Bios
// FIXME: because PRId<0x23, the bit 0 of sio2 don't get updated 0xBF808284
SetResultSize(1);
cdvd.Result[0] = 0;
break;
// case 0x25: // cdvdman_call120 (1:1) - In V10 Bios
// break;
// case 0x26: // cdvdman_call128 (0,3) - In V10 Bios
// break;
// case 0x27: // cdvdman_call148 (0:13) - In V10 Bios
// break;
// case 0x28: // cdvdman_call150 (1:1) - In V10 Bios
// break;
case 0x29: //sceCdNoticeGameStart (1:1)
SetResultSize(1);
cdvd.Result[0] = 0;
break;
// case 0x2C: //sceCdXBSPowerCtl (2:2)
// break;
// case 0x2D: //sceCdXLEDCtl (2:2)
// break;
// case 0x2E: //sceCdBuzzerCtl (0:1)
// break;
// case 0x2F: //cdvdman_call167 (16:1)
// break;
// case 0x30: //cdvdman_call169 (1:9)
// break;
case 0x31: //sceCdSetMediumRemoval (1:1)
SetResultSize(1);
cdvd.Result[0] = 0;
break;
case 0x32: //sceCdGetMediumRemoval (0:2)
SetResultSize(2);
cdvd.Result[0] = 0;
//cdvd.Result[0] = 0; // fixme: I'm pretty sure that the same variable shouldn't be set twice here. Perhaps cdvd.Result[1]?
break;
// case 0x33: //sceCdXDVRPReset (1:1)
// break;
case 0x36: //cdvdman_call189 [__sceCdReadRegionParams - made up name] (0:15) i think it is 16, not 15
SetResultSize(15);
cdvdGetMechaVer(&cdvd.Result[1]);
cdvd.Result[0] = cdvdReadRegionParams(&cdvd.Result[3]);//size==8
Console::WriteLn("REGION PARAMS = %s %s", params mg_zones[cdvd.Result[1]], &cdvd.Result[3]);
cdvd.Result[1] = 1 << cdvd.Result[1]; //encryption zone; see offset 0x1C in encrypted headers
//////////////////////////////////////////
cdvd.Result[2] = 0; //??
// cdvd.Result[3] == ROMVER[4] == *0xBFC7FF04
// cdvd.Result[4] == OSDVER[4] == CAP Jjpn, Aeng, Eeng, Heng, Reng, Csch, Kkor?
// cdvd.Result[5] == OSDVER[5] == small
// cdvd.Result[6] == OSDVER[6] == small
// cdvd.Result[7] == OSDVER[7] == small
// cdvd.Result[8] == VERSTR[0x22] == *0xBFC7FF52
// cdvd.Result[9] == DVDID J U O E A R C M
// cdvd.Result[10]== 0; //??
cdvd.Result[11] = 0; //??
cdvd.Result[12] = 0; //??
//////////////////////////////////////////
cdvd.Result[13] = 0; //0xFF - 77001
cdvd.Result[14] = 0; //??
break;
case 0x37: //called from EECONF [sceCdReadMAC - made up name] (0:9)
SetResultSize(9);
cdvd.Result[0] = cdvdReadMAC(&cdvd.Result[1]);
break;
case 0x38: //used to fix the MAC back after accidentally trashed it :D [sceCdWriteMAC - made up name] (8:1)
SetResultSize(1);
cdvd.Result[0] = cdvdWriteMAC(&cdvd.Param[0]);
break;
case 0x3E: //[__sceCdWriteRegionParams - made up name] (15:1) [Florin: hum, i was expecting 14:1]
SetResultSize(1);
cdvd.Result[0] = cdvdWriteRegionParams(&cdvd.Param[2]);
break;
case 0x40: // CdOpenConfig (3:1)
SetResultSize(1);
cdvd.CReadWrite = cdvd.Param[0];
cdvd.COffset = cdvd.Param[1];
cdvd.CNumBlocks = cdvd.Param[2];
cdvd.CBlockIndex= 0;
cdvd.Result[0] = 0;
break;
case 0x41: // CdReadConfig (0:16)
SetResultSize(16);
cdvdReadConfig(&cdvd.Result[0]);
break;
case 0x42: // CdWriteConfig (16:1)
SetResultSize(1);
cdvd.Result[0] = cdvdWriteConfig(&cdvd.Param[0]);
break;
case 0x43: // CdCloseConfig (0:1)
SetResultSize(1);
cdvd.CReadWrite = 0;
cdvd.COffset = 0;
cdvd.CNumBlocks = 0;
cdvd.CBlockIndex= 0;
cdvd.Result[0] = 0;
break;
case 0x80: // secrman: __mechacon_auth_0x80
SetResultSize(1);//in:1
cdvd.mg_datatype = 0;//data
cdvd.Result[0] = 0;
break;
case 0x81: // secrman: __mechacon_auth_0x81
SetResultSize(1);//in:1
cdvd.mg_datatype = 0;//data
cdvd.Result[0] = 0;
break;
case 0x82: // secrman: __mechacon_auth_0x82
SetResultSize(1);//in:16
cdvd.Result[0] = 0;
break;
case 0x83: // secrman: __mechacon_auth_0x83
SetResultSize(1);//in:8
cdvd.Result[0] = 0;
break;
case 0x84: // secrman: __mechacon_auth_0x84
SetResultSize(1+8+4);//in:0
cdvd.Result[0] = 0;
cdvd.Result[1] = 0x21;
cdvd.Result[2] = 0xdc;
cdvd.Result[3] = 0x31;
cdvd.Result[4] = 0x96;
cdvd.Result[5] = 0xce;
cdvd.Result[6] = 0x72;
cdvd.Result[7] = 0xe0;
cdvd.Result[8] = 0xc8;
cdvd.Result[9] = 0x69;
cdvd.Result[10] = 0xda;
cdvd.Result[11] = 0x34;
cdvd.Result[12] = 0x9b;
break;
case 0x85: // secrman: __mechacon_auth_0x85
SetResultSize(1+4+8);//in:0
cdvd.Result[0] = 0;
cdvd.Result[1] = 0xeb;
cdvd.Result[2] = 0x01;
cdvd.Result[3] = 0xc7;
cdvd.Result[4] = 0xa9;
cdvd.Result[ 5] = 0x3f;
cdvd.Result[ 6] = 0x9c;
cdvd.Result[ 7] = 0x5b;
cdvd.Result[ 8] = 0x19;
cdvd.Result[ 9] = 0x31;
cdvd.Result[10] = 0xa0;
cdvd.Result[11] = 0xb3;
cdvd.Result[12] = 0xa3;
break;
case 0x86: // secrman: __mechacon_auth_0x86
SetResultSize(1);//in:16
cdvd.Result[0] = 0;
break;
case 0x87: // secrman: __mechacon_auth_0x87
SetResultSize(1);//in:8
cdvd.Result[0] = 0;
break;
case 0x8D: // sceMgWriteData
SetResultSize(1);//in:length<=16
if (cdvd.mg_size + cdvd.ParamC > cdvd.mg_maxsize)
{
cdvd.Result[0] = 0x80;
}
else
{
memcpy_fast(cdvd.mg_buffer + cdvd.mg_size, cdvd.Param, cdvd.ParamC);
cdvd.mg_size += cdvd.ParamC;
cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
}
break;
case 0x8E: // sceMgReadData
SetResultSize( std::min(16, cdvd.mg_size) );
memcpy_fast(cdvd.Result, cdvd.mg_buffer, cdvd.ResultC);
cdvd.mg_size -= cdvd.ResultC;
memcpy_fast(cdvd.mg_buffer, cdvd.mg_buffer+cdvd.ResultC, cdvd.mg_size);
break;
case 0x88: // secrman: __mechacon_auth_0x88 //for now it is the same; so, fall;)
case 0x8F: // secrman: __mechacon_auth_0x8F
SetResultSize(1);//in:0
if (cdvd.mg_datatype == 1) // header data
{
u64* psrc, *pdst;
int bit_ofs, i;
if ((cdvd.mg_maxsize != cdvd.mg_size)||(cdvd.mg_size < 0x20) || (cdvd.mg_size != *(u16*)&cdvd.mg_buffer[0x14]))
{
fail_pol_cal();
break;
}
Console::Write("[MG] ELF_size=0x%X Hdr_size=0x%X unk=0x%X flags=0x%X count=%d zones=",
params *(u32*)&cdvd.mg_buffer[0x10], *(u16*)&cdvd.mg_buffer[0x14], *(u16*)&cdvd.mg_buffer[0x16],
*(u16*)&cdvd.mg_buffer[0x18], *(u16*)&cdvd.mg_buffer[0x1A]);
for (i=0; i<8; i++)
{
if (cdvd.mg_buffer[0x1C] & (1<<i)) Console::Write("%s ", params mg_zones[i]);
}
Console::Newline();
bit_ofs = mg_BIToffset(cdvd.mg_buffer);
psrc = (u64*)&cdvd.mg_buffer[bit_ofs-0x20];
pdst = (u64*)cdvd.mg_kbit;
pdst[0] = psrc[0];
pdst[1] = psrc[1];
//memcpy(cdvd.mg_kbit, &cdvd.mg_buffer[bit_ofs-0x20], 0x10);
pdst = (u64*)cdvd.mg_kcon;
pdst[0] = psrc[2];
pdst[1] = psrc[3];
//memcpy(cdvd.mg_kcon, &cdvd.mg_buffer[bit_ofs-0x10], 0x10);
if ((cdvd.mg_buffer[bit_ofs+5] || cdvd.mg_buffer[bit_ofs+6] || cdvd.mg_buffer[bit_ofs+7]) ||
(cdvd.mg_buffer[bit_ofs+4] * 16 + bit_ofs + 8 + 16 != *(u16*)&cdvd.mg_buffer[0x14]))
{
fail_pol_cal();
break;
}
}
cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
break;
case 0x90: // sceMgWriteHeaderStart
SetResultSize(1);//in:5
cdvd.mg_size = 0;
cdvd.mg_datatype = 1;//header data
Console::WriteLn("[MG] hcode=%d cnum=%d a2=%d length=0x%X", params
cdvd.Param[0], cdvd.Param[3], cdvd.Param[4], cdvd.mg_maxsize = cdvd.Param[1] | (((int)cdvd.Param[2])<<8));
cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
break;
case 0x91: // sceMgReadBITLength
{
SetResultSize(3);//in:0
int bit_ofs = mg_BIToffset(cdvd.mg_buffer);
memcpy_fast(cdvd.mg_buffer, &cdvd.mg_buffer[bit_ofs], 8+16*cdvd.mg_buffer[bit_ofs+4]);
cdvd.mg_maxsize = 0; // don't allow any write
cdvd.mg_size = 8+16*cdvd.mg_buffer[4];//new offset, i just moved the data
Console::WriteLn("[MG] BIT count=%d", params cdvd.mg_buffer[4]);
cdvd.Result[0] = (cdvd.mg_datatype == 1) ? 0 : 0x80; // 0 complete ; 1 busy ; 0x80 error
cdvd.Result[1] = (cdvd.mg_size >> 0) & 0xFF;
cdvd.Result[2] = (cdvd.mg_size >> 8) & 0xFF;
break;
}
case 0x92: // sceMgWriteDatainLength
SetResultSize(1);//in:2
cdvd.mg_size = 0;
cdvd.mg_datatype = 0;//data (encrypted)
cdvd.mg_maxsize = cdvd.Param[0] | (((int)cdvd.Param[1])<<8);
cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
break;
case 0x93: // sceMgWriteDataoutLength
SetResultSize(1);//in:2
if (((cdvd.Param[0] | (((int)cdvd.Param[1])<<8)) == cdvd.mg_size) && (cdvd.mg_datatype == 0))
{
cdvd.mg_maxsize = 0; // don't allow any write
cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
}
else
{
cdvd.Result[0] = 0x80;
}
break;
case 0x94: // sceMgReadKbit - read first half of BIT key
SetResultSize(1+8);//in:0
cdvd.Result[0] = 0;
((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kbit)[0];
((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kbit)[1];
//memcpy(cdvd.Result+1, cdvd.mg_kbit, 8);
break;
case 0x95: // sceMgReadKbit2 - read second half of BIT key
SetResultSize(1+8);//in:0
cdvd.Result[0] = 0;
((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kbit+8))[0];
((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kbit+8))[1];
//memcpy(cdvd.Result+1, cdvd.mg_kbit+8, 8);
break;
case 0x96: // sceMgReadKcon - read first half of content key
SetResultSize(1+8);//in:0
cdvd.Result[0] = 0;
((int*)(cdvd.Result+1))[0] = ((int*)cdvd.mg_kcon)[0];
((int*)(cdvd.Result+1))[1] = ((int*)cdvd.mg_kcon)[1];
//memcpy(cdvd.Result+1, cdvd.mg_kcon, 8);
break;
case 0x97: // sceMgReadKcon2 - read second half of content key
SetResultSize(1+8);//in:0
cdvd.Result[0] = 0;
((int*)(cdvd.Result+1))[0] = ((int*)(cdvd.mg_kcon+8))[0];
((int*)(cdvd.Result+1))[1] = ((int*)(cdvd.mg_kcon+8))[1];
//memcpy(cdvd.Result+1, cdvd.mg_kcon+8, 8);
break;
default:
// fake a 'correct' command
SetResultSize(1); //in:0
cdvd.Result[0] = 0; // 0 complete ; 1 busy ; 0x80 error
Console::WriteLn("SCMD Unknown %x", params rt);
break;
} // end switch
//Console::WriteLn("SCMD - 0x%x\n", params rt);
cdvd.ParamP = 0;
cdvd.ParamC = 0;
}
static __forceinline void cdvdWrite17(u8 rt) { // SDATAIN
CDR_LOG("cdvdWrite17(SDataIn) %x", rt);
if (cdvd.ParamP < 32) {
cdvd.Param[cdvd.ParamP++] = rt;
cdvd.ParamC++;
}
}
static __forceinline void cdvdWrite18(u8 rt) { // SDATAOUT
CDR_LOG("cdvdWrite18(SDataOut) %x", rt);
Console::WriteLn("*PCSX2* SDATAOUT");
}
static __forceinline void cdvdWrite3A(u8 rt) { // DEC-SET
CDR_LOG("cdvdWrite3A(DecSet) %x", rt);
cdvd.decSet = rt;
Console::WriteLn("DecSet Write: %02X", params cdvd.decSet);
}
void cdvdWrite(u8 key, u8 rt)
{
switch (key)
{
case 0x04: cdvdWrite04(rt); break;
case 0x05: cdvdWrite05(rt); break;
case 0x06: cdvdWrite06(rt); break;
case 0x07: cdvdWrite07(rt); break;
case 0x08: cdvdWrite08(rt); break;
case 0x0A: cdvdWrite0A(rt); break;
case 0x0F: cdvdWrite0F(rt); break;
case 0x14: cdvdWrite14(rt); break;
case 0x16: cdvdWrite16(rt); break;
case 0x17: cdvdWrite17(rt); break;
case 0x18: cdvdWrite18(rt); break;
case 0x3A: cdvdWrite3A(rt); break;
default:
Console::Notice("IOP Unknown 8bit write to addr 0x1f4020%x = 0x%x", params key, rt);
break;
}
}