Files
archived-pcsx2/pcsx2/CDVD/CDVD.cpp
ramapcsx2 26392e7f3e Change various logs to sound "nicer".
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@5160 96395faa-99c1-11dd-bbfe-3dabce05a288
2012-04-17 17:55:51 +00:00

2088 lines
56 KiB
C++

/* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team
*
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
* PCSX2 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 PCSX2.
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "PrecompiledHeader.h"
#include "IopCommon.h"
#include "AppConfig.h"
#include <ctype.h>
#include <wx/datetime.h>
#include "CDVD.h"
#include "CDVD_internal.h"
#include "CDVDisoReader.h"
#include "GS.h" // for gsRegionMode
#include "Elfheader.h"
#include "ps2/BiosTools.h"
#include "GameDatabase.h"
// This typically reflects the Sony-assigned serial code for the Disc, if one exists.
// (examples: SLUS-2113, etc).
// If the disc is homebrew then it probably won't have a valid serial; in which case
// this string will be empty.
wxString DiscSerial;
static cdvdStruct cdvd;
static __fi void SetResultSize(u8 size)
{
cdvd.ResultC = size;
cdvd.ResultP = 0;
cdvd.sDataIn&=~0x40;
}
static void CDVDREAD_INT(int eCycle)
{
// Give it an arbitary FAST value. Good for ~5000kb/s in ULE when copying a file from CDVD to HDD
// Keep long seeks out though, as games may try to push dmas while seeking. (Tales of the Abyss)
if (EmuConfig.Speedhacks.fastCDVD) {
if(eCycle < Cdvd_FullSeek_Cycles)
eCycle = 3000;
}
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 );
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()
{
// get the name of the bios file
wxFileName mecfile(EmuConfig.BiosFilename);
mecfile.SetExt( L"mec" );
const wxString fname( mecfile.GetFullPath() );
// if file doesnt exist, create empty one
FILE* fd = wxFopen(fname, L"r+b");
if (fd == NULL)
{
Console.Warning("MEC File Not Found, creating substitute...");
fd = wxFopen(fname, L"wb");
if (fd == NULL)
throw Exception::CannotCreateStream(fname);
fputc(0x03, fd);
fputc(0x06, fd);
fputc(0x02, fd);
fputc(0x00, fd);
}
return fd;
}
static void cdvdGetMechaVer(u8* ver)
{
FILE* fd = _cdvdOpenMechaVer();
fseek(fd, 0, SEEK_SET);
fread(ver, 1, 4, fd);
fclose(fd);
}
// Throws Exception::CannotCreateStream if the file cannot be opened for reading, or cannot
// be created for some reason.
FILE* _cdvdOpenNVM()
{
wxFileName nvmfile(EmuConfig.BiosFilename);
nvmfile.SetExt( L"nvm" );
const wxString fname( nvmfile.GetFullPath() );
// if file doesn't exist, create empty one
FILE* fd = wxFopen(fname, L"r+b");
if (fd == NULL)
{
Console.Warning("NVM File Not Found, Creating Blank File");
fd = wxFopen(fname, L"wb");
if (fd == NULL)
throw Exception::CannotCreateStream(fname);
for (int i=0; i<1024; i++) fputc(0, fd);
}
return fd;
}
//
// the following 'cdvd' functions all return 0 if successful
//
static void cdvdReadNVM(u8 *dst, int offset, int bytes) {
FILE* fd = _cdvdOpenNVM();
fseek(fd, offset, SEEK_SET);
fread(dst, 1, bytes, fd);
fclose(fd);
}
static void cdvdWriteNVM(const u8 *src, int offset, int bytes) {
FILE* fd = _cdvdOpenNVM();
fseek(fd, offset, SEEK_SET);
fwrite(src, 1, bytes, fd);
fclose(fd);
}
NVMLayout* getNvmLayout()
{
NVMLayout* nvmLayout = NULL;
s32 nvmIdx;
for(nvmIdx=0; nvmIdx<NVM_FORMAT_MAX; nvmIdx++)
{
if(nvmlayouts[nvmIdx].biosVer <= BiosVersion)
nvmLayout = &nvmlayouts[nvmIdx];
}
return nvmLayout;
}
void getNvmData(u8* buffer, s32 offset, s32 size, s32 fmtOffset)
{
// find the correct bios version
NVMLayout* nvmLayout = getNvmLayout();
// get data from eeprom
cdvdReadNVM(buffer, *(s32*)(((u8*)nvmLayout)+fmtOffset) + offset, size);
}
void setNvmData(const u8* buffer, s32 offset, s32 size, s32 fmtOffset)
{
// find the correct bios version
NVMLayout* nvmLayout = getNvmLayout();
// set data in eeprom
cdvdWriteNVM(buffer, *(s32*)(((u8*)nvmLayout)+fmtOffset) + offset, size);
}
static void cdvdReadConsoleID(u8* id)
{
getNvmData(id, 0, 8, offsetof(NVMLayout, consoleId));
}
static void cdvdWriteConsoleID(const u8* id)
{
setNvmData(id, 0, 8, offsetof(NVMLayout, consoleId));
}
static void cdvdReadILinkID(u8* id)
{
getNvmData(id, 0, 8, offsetof(NVMLayout, ilinkId));
}
static void cdvdWriteILinkID(const u8* id)
{
setNvmData(id, 0, 8, offsetof(NVMLayout, ilinkId));
}
static void cdvdReadModelNumber(u8* num, s32 part)
{
getNvmData(num, part, 8, offsetof(NVMLayout, modelNum));
}
static void cdvdWriteModelNumber(const u8* num, s32 part)
{
setNvmData(num, part, 8, offsetof(NVMLayout, modelNum));
}
static void cdvdReadRegionParams(u8* num)
{
getNvmData(num, 0, 8, offsetof(NVMLayout,regparams));
}
static void cdvdWriteRegionParams(const u8* num)
{
setNvmData(num, 0, 8, offsetof(NVMLayout,regparams));
}
static void cdvdReadMAC(u8* num)
{
getNvmData(num, 0, 8, offsetof(NVMLayout,mac));
}
static void cdvdWriteMAC(const u8* num)
{
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:
getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config0));
break;
case 2:
getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config2));
break;
default:
getNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config1));
}
return 0;
}
s32 cdvdWriteConfig(const u8* config)
{
// make sure its in write mode && the block index is in bounds
if ((cdvd.CReadWrite != 1) || (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:
setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config0));
break;
case 2:
setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config2));
break;
default:
setNvmData(config, (cdvd.CBlockIndex++)*16, 16, offsetof(NVMLayout, config1));
}
return 0;
}
static MutexRecursive Mutex_NewDiskCB;
// Sets ElfCRC to the CRC of the game bound to the CDVD plugin.
static __fi ElfObject* loadElf( const wxString filename )
{
if (filename.StartsWith(L"host"))
return new ElfObject(filename.After(':'), Path::GetFileSize(filename.After(':')));
// Mimic PS2 behavior!
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
//
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
// or anything else. Its all ignored.
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
// or lower level filesystem APIs (fortunately that doesn't affect us).
//
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
// be sufficient (no known games have their ELF binary as anything but version ;1)
const wxString fixedname( wxStringTokenizer(filename, L';').GetNextToken() + L";1" );
if( fixedname != filename )
Console.WriteLn( Color_Blue, "(LoadELF) Non-conforming version suffix detected and replaced." );
IsoFSCDVD isofs;
IsoFile file(isofs, fixedname);
return new ElfObject(fixedname, file);
}
static __fi void _reloadElfInfo(wxString elfpath)
{
ScopedPtr<ElfObject> elfptr;
// Now's a good time to reload the ELF info...
ScopedLock locker( Mutex_NewDiskCB );
if (elfpath == LastELF) return;
LastELF = elfpath;
wxString fname = elfpath.AfterLast('\\');
if (!fname)
fname = elfpath.AfterLast('/');
if (!fname)
fname = elfpath.AfterLast(':');
if (fname.Matches(L"????_???.??*"))
DiscSerial = fname(0,4) + L"-" + fname(5,3) + fname(9,2);
elfptr = loadElf(elfpath);
ElfCRC = elfptr->getCRC();
ElfEntry = elfptr->header.e_entry;
Console.WriteLn( Color_StrongBlue, L"ELF (%s) Game CRC = 0x%08X, EntryPoint = 0x%08X", elfpath.c_str(), ElfCRC, ElfEntry);
// Note: Do not load game database info here. This code is generic and called from
// BIOS key encryption as well as eeloadReplaceOSDSYS. The first is actually still executing
// BIOS code, and patches and cheats should not be applied yet. (they are applied when
// eeGameStarting is invoked, which is when the VM starts executing the actual game ELF
// binary).
}
void cdvdReloadElfInfo(wxString elfoverride)
{
// called from context of executing VM code (recompilers), so we need to trap exceptions
// and route them through the VM's exception handler. (needed for non-SEH platforms, such
// as Linux/GCC)
try
{
if (!elfoverride.IsEmpty())
{
_reloadElfInfo(elfoverride);
return;
}
wxString elfpath;
u32 discType = GetPS2ElfName(elfpath);
if(discType==1)
{
// Is a PS1 disc.
if (!ENABLE_LOADING_PS1_GAMES)
Cpu->ThrowException( Exception::RuntimeError()
.SetDiagMsg(L"PSX game discs are not supported by PCSX2.")
.SetUserMsg(pxE( "!Notice:PsxDisc",
L"Playstation game discs are not supported by PCSX2. If you want to emulate PSX games "
L"then you'll have to download a PSX-specific emulator, such as ePSXe or PCSX.")
)
);
//Console.Error( "Playstation1 game discs are not supported by PCSX2." );
}
// Isn't a disc we recognize?
if(discType == 0) return;
// Recognized and PS2 (BOOT2). Good job, user.
_reloadElfInfo(elfpath);
}
catch (Exception::FileNotFound& e)
{
pxFail( "Not in my back yard!" );
Cpu->ThrowException(e);
}
}
static __fi s32 StrToS32(const wxString& str, int base = 10)
{
long l;
str.ToLong(&l, base);
return l;
}
void cdvdReadKey(u8, u16, u32 arg2, u8* key)
{
s32 numbers=0, letters=0;
u32 key_0_3;
u8 key_4, key_14;
cdvdReloadElfInfo();
// clear key values
memzero_ptr<16>(key);
if (!DiscSerial.IsEmpty())
{
// convert the number characters to a real 32 bit number
numbers = StrToS32(DiscSerial(5,5));
// combine the lower 7 bits of each char
// to make the 4 letters fit into a single u32
letters = (s32)((DiscSerial[3]&0x7F)<< 0) |
(s32)((DiscSerial[2]&0x7F)<< 7) |
(s32)((DiscSerial[1]&0x7F)<<14) |
(s32)((DiscSerial[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
// 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;
switch (arg2)
{
case 75:
key[14] = key_14;
key[15] = 0x05;
break;
// case 3075:
// key[15] = 0x01;
// break;
case 4246:
// 0x0001F2F707 = sector 0x0001F2F7 dec 0x07
key[ 0] = 0x07;
key[ 1] = 0xF7;
key[ 2] = 0xF2;
key[ 3] = 0x01;
key[ 4] = 0x00;
key[15] = 0x01;
break;
default:
key[15] = 0x01;
break;
}
DevCon.WriteLn( "CDVD.KEY = %02X,%02X,%02X,%02X,%02X,%02X,%02X",
cdvd.Key[0],cdvd.Key[1],cdvd.Key[2],cdvd.Key[3],cdvd.Key[4],cdvd.Key[14],cdvd.Key[15] );
}
s32 cdvdGetToc(void* toc)
{
s32 ret = CDVD->getTOC(toc);
if (ret == -1) ret = 0x80;
return ret;
}
s32 cdvdReadSubQ(s32 lsn, cdvdSubQ* subq)
{
s32 ret = CDVD->readSubQ(lsn, subq);
if (ret == -1) ret = 0x80;
return ret;
}
s32 cdvdCtrlTrayOpen()
{
DevCon.WriteLn( Color_Green, L"Open virtual disk tray");
DiscSwapTimerSeconds = cdvd.RTC.second; // remember the PS2 time when this happened
cdvd.Status = CDVD_STATUS_TRAY_OPEN;
cdvd.Ready = CDVD_NOTREADY;
return 0; // needs to be 0 for success according to homebrew test "CDVD"
}
s32 cdvdCtrlTrayClose()
{
DevCon.WriteLn( Color_Green, L"Close virtual disk tray");
cdvd.Status = CDVD_STATUS_PAUSE;
cdvd.Ready = CDVD_READY1;
cdvd.TrayTimeout = 0; // Reset so it can't get closed twice by cdvdVsync()
return 0; // needs to be 0 for success according to homebrew test "CDVD"
}
// Some legacy function, not used anymore
s32 cdvdGetTrayStatus()
{
/*s32 ret = CDVD->getTrayStatus();
if (ret == -1)
return(CDVD_TRAY_CLOSE);
else
return(ret);*/
return -1;
}
// Note: Is tray status being kept as a var here somewhere?
// Yep, and sceCdTrayReq needs it to detect tray state changes (rama)
// cdvdNewDiskCB() can update it's status as well...
// Modified by (efp) - 16/01/2006
static __fi void cdvdGetDiskType()
{
cdvd.Type = DoCDVDdetectDiskType();
}
// 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)
{
*dualType = 0;
*layer1Start = 0;
return CDVD->getDualInfo(dualType,layer1Start);
}
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(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 );
// CDVD internally uses GMT+9. If you think the time's wrong, you're wrong.
// Set up your time zone and winter/summer in the BIOS. No PS2 BIOS I know of features automatic DST.
wxDateTime curtime( wxDateTime::GetTimeNow() );
cdvd.RTC.second = (u8)curtime.GetSecond();
cdvd.RTC.minute = (u8)curtime.GetMinute();
cdvd.RTC.hour = (u8)curtime.GetHour(wxDateTime::GMT9);
cdvd.RTC.day = (u8)curtime.GetDay(wxDateTime::GMT9);
cdvd.RTC.month = (u8)curtime.GetMonth(wxDateTime::GMT9) + 1; // WX returns Jan as "0"
cdvd.RTC.year = (u8)(curtime.GetYear(wxDateTime::GMT9) - 2000);
}
struct Freeze_v10Compat
{
u8 Action;
u32 SeekToSector;
u32 ReadTime;
bool Spinning;
};
void SaveStateBase::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 = DoCDVDreadTrack( cdvd.Readed ? cdvd.Sector : cdvd.SeekToSector, cdvd.ReadMode);
}
}
static void cdvdDetectDisk()
{
wxString str;
cdvd.Type = DoCDVDdetectDiskType();
cdvdReloadElfInfo();
}
void cdvdNewDiskCB()
{
ScopedTryLock lock( Mutex_NewDiskCB );
if( lock.Failed() ) return;
DoCDVDresetDiskTypeCache();
cdvdDetectDisk();
}
static void mechaDecryptBytes( u32 madr, int size )
{
int shiftAmount = (cdvd.decSet>>4) & 7;
int doXor = (cdvd.decSet) & 1;
int doShift = (cdvd.decSet) & 2;
u8* curval = iopPhysMem( madr );
for( int i=0; i<size; ++i, ++curval )
{
if( doXor ) *curval ^= cdvd.Key[4];
if( doShift ) *curval = (*curval >> shiftAmount) | (*curval << (8-shiftAmount) );
}
}
int cdvdReadSector() {
s32 bcr;
CDVD_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) {
CDVD_LOG( "READBLOCK: bcr < cdvd.BlockSize; %x < %x", bcr, cdvd.BlockSize );
if (HW_DMA3_CHCR & 0x01000000) {
HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3);
}
return -1;
}
//if( (HW_DMA3_CHCR & 0x01000000) == 0 ) {
// // DMA3 problem?
// Console.Warning( "CDVD READ - DMA3 transfer off (try again)\n" );
//}
// 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
{
// Assuming 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_const(&mdest[12], cdr.Transfer, 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.Transfer, 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", 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.
__fi void cdvdActionInterrupt()
{
switch( cdvd.Action )
{
case cdvdAction_Seek:
cdvd.Spinning = true;
cdvd.Ready = CDVD_READY1; //check (rama)
cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE;
break;
case cdvdAction_Standby:
DevCon.Warning("CDVD Standby Call");
cdvd.Spinning = true; //check (rama)
cdvd.Ready = CDVD_READY1; //check (rama)
cdvd.Sector = cdvd.SeekToSector;
cdvd.Status = CDVD_STATUS_PAUSE;
break;
case cdvdAction_Stop:
cdvd.Spinning = false;
cdvd.Ready = CDVD_READY1;
cdvd.Sector = 0;
cdvd.Status = CDVD_STATUS_STOP;
break;
case cdvdAction_Break:
// Make sure the cdvd action state is pretty well cleared:
DevCon.WriteLn("CDVD Break Call");
cdvd.Reading = 0;
cdvd.Readed = 0;
cdvd.Ready = CDVD_READY2; // should be CDVD_READY1 or something else?
cdvd.Status = CDVD_STATUS_STOP;
cdvd.RErr = 0;
cdvd.nCommand = 0;
break;
}
cdvd.Action = cdvdAction_None;
cdvd.PwOff |= 1<<Irq_CommandComplete;
psxHu32(0x1070)|= 0x4;
}
// inlined due to being referenced in only one place.
__fi void cdvdReadInterrupt()
{
//Console.WriteLn("cdvdReadInterrupt %x %x %x %x %x", 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_PAUSE; // check (rama)
cdvd.Status = CDVD_STATUS_READ | CDVD_STATUS_SPIN; // Time Crisis 2
cdvd.Sector = cdvd.SeekToSector;
CDVD_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 )
{
while( (cdvd.RErr = DoCDVDgetBuffer(cdr.Transfer)), cdvd.RErr == -2 )
{
// not finished yet ... block on the read until it finishes.
Threading::Sleep( 0 );
Threading::SpinWait();
}
}
if (cdvd.RErr == -1)
{
cdvd.RetryCntP++;
if (cdvd.RetryCntP <= cdvd.RetryCnt)
{
CDVD_LOG( "CDVD read err, retrying... (attempt %d of %d)", cdvd.RetryCntP, cdvd.RetryCnt );
cdvd.RErr = DoCDVDreadTrack(cdvd.Sector, cdvd.ReadMode);
CDVDREAD_INT(cdvd.ReadTime);
}
else
Console.Error("CDVD READ ERROR, sector = 0x%08x", cdvd.Sector);
return;
}
cdvd.Reading = false;
// Any other value besides 0 should be considered invalid here (wtf is that wacky
// plugin trying to do?)
pxAssert( cdvd.RErr == 0 );
}
if (cdvd.nSectors > 0)
{
if (cdvdReadSector() == -1)
{
// This means that the BCR/DMA hasn't finished yet, and rather than fire off the
// sector-finished notice too early (which might overwrite game data) we delay a
// bit and try to read the sector again later.
// An arbitrary delay of some number of cycles probably makes more sense here,
// but for now it's based on the cdvd.ReadTime value. -- air
pxAssert((int)cdvd.ReadTime > 0 );
CDVDREAD_INT(cdvd.ReadTime/4);
return;
}
cdvd.Sector++;
}
if (--cdvd.nSectors <= 0)
{
cdvd.PwOff |= 1<<Irq_CommandComplete;
psxHu32(0x1070)|= 0x4;
HW_DMA3_CHCR &= ~0x01000000;
psxDmaInterrupt(3);
cdvd.Ready = CDVD_READY2;
cdvd.Status = CDVD_STATUS_PAUSE; // Needed here but could be smth else than Pause (rama)
// All done! :D
return;
}
cdvd.RetryCntP = 0;
cdvd.Reading = 1;
cdvd.RErr = DoCDVDreadTrack(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_STOP; // before r4961
//cdvd.Status = CDVD_STATUS_SEEK | CDVD_STATUS_SPIN; // Time Crisis 2 // but breaks ICO NTSC
cdvd.Status = CDVD_STATUS_PAUSE; // best so far in my tests (rama)
if( !cdvd.Spinning )
{
CDVD_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
CDVD_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d [FULL]", cdvd.SeekToSector, cdvd.Sector, delta );
seektime = Cdvd_FullSeek_Cycles;
}
else
{
CDVD_LOG( "CdSeek Begin > to sector %d, from %d - delta=%d [FAST]", cdvd.SeekToSector, cdvd.Sector, delta );
seektime = Cdvd_FastSeek_Cycles;
}
}
else
{
CDVD_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_PAUSE;
cdvd.Status = CDVD_STATUS_READ | CDVD_STATUS_SPIN; // Time Crisis 2
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 < ((gsRegionMode == Region_NTSC) ? 60 : 50)) return;
cdvd.RTCcount = 0;
if ( cdvd.Status == CDVD_STATUS_TRAY_OPEN )
{
cdvd.TrayTimeout++;
}
if (cdvd.TrayTimeout > 3)
{
cdvdCtrlTrayClose();
cdvd.TrayTimeout = 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 <= (cdvd.RTC.month == 2 && cdvd.RTC.year % 4 == 0 ? 29 : 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 __fi 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];
}
CDVD_LOG("cdvdRead18(SDataOut) %x (ResultC=%d, ResultP=%d)", ret, cdvd.ResultC, cdvd.ResultP);
return ret;
}
u8 cdvdRead(u8 key)
{
switch (key)
{
case 0x04: // NCOMMAND
CDVD_LOG("cdvdRead04(NCMD) %x", cdvd.nCommand);
return cdvd.nCommand;
break;
case 0x05: // N-READY
CDVD_LOG("cdvdRead05(NReady) %x", cdvd.Ready);
return cdvd.Ready;
break;
case 0x06: // ERROR
CDVD_LOG("cdvdRead06(Error) %x", cdvd.Error);
return cdvd.Error;
break;
case 0x07: // BREAK
CDVD_LOG("cdvdRead07(Break) %x", 0);
return 0;
break;
case 0x08: // STATUS
CDVD_LOG("cdvdRead08(Status) %x", cdvd.Status);
return cdvd.Status;
break;
case 0x0A: // STATUS
CDVD_LOG("cdvdRead0A(Status) %x", cdvd.Status);
return cdvd.Status;
break;
case 0x0B: // TRAY-STATE (if tray has been opened)
{
CDVD_LOG("cdvdRead0B(Tray) (1 open, 0 closed): %x", cdvd.Status);
if (cdvd.Status == CDVD_STATUS_TRAY_OPEN)
return 1;
else
return 0;
break;
}
case 0x0C: // CRT MINUTE
CDVD_LOG("cdvdRead0C(Min) %x", itob((u8)(cdvd.Sector/(60*75))));
return itob((u8)(cdvd.Sector/(60*75)));
break;
case 0x0D: // CRT SECOND
CDVD_LOG("cdvdRead0D(Sec) %x", itob((u8)((cdvd.Sector/75)%60)+2));
return itob((u8)((cdvd.Sector/75)%60)+2);
break;
case 0x0E: // CRT FRAME
CDVD_LOG("cdvdRead0E(Frame) %x", itob((u8)(cdvd.Sector%75)));
return itob((u8)(cdvd.Sector%75));
break;
case 0x0F: // TYPE
CDVD_LOG("cdvdRead0F(Disc Type) %x", cdvd.Type);
cdvdGetDiskType();
return cdvd.Type;
break;
case 0x13: // UNKNOWN
CDVD_LOG("cdvdRead13(Unknown) %x", 4);
return 4;
break;
case 0x15: // RSV
CDVD_LOG("cdvdRead15(RSV)");
return 0x01; // | 0x80 for ATAPI mode
break;
case 0x16: // SCOMMAND
CDVD_LOG("cdvdRead16(SCMD) %x", cdvd.sCommand);
return cdvd.sCommand;
break;
case 0x17: // SREADY
CDVD_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;
CDVD_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;
CDVD_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;
CDVD_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)
CDVD_LOG("cdvdRead38(KeysValid) %x", cdvd.Key[15]);
return cdvd.Key[15];
break;
case 0x39: // KEY-XOR
CDVD_LOG("cdvdRead39(KeyXor) %x", cdvd.KeyXor);
return cdvd.KeyXor;
break;
case 0x3A: // DEC_SET
CDVD_LOG("cdvdRead3A(DecSet) %x", 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", key );
return 0;
break;
}
}
static void cdvdWrite04(u8 rt) { // NCOMMAND
CDVD_LOG("cdvdWrite04: NCMD %s (%x) (ParamP = %x)", nCmdName[rt], rt, cdvd.ParamP);
cdvd.nCommand = rt;
// Why fiddle with Status and PwOff here at all? (rama)
cdvd.Status = cdvd.Spinning ? CDVD_STATUS_SPIN : CDVD_STATUS_STOP; // checkme
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.Warning( "CdStandby : %d", rt );
cdvd.Action = cdvdAction_Standby;
cdvd.ReadTime = cdvdBlockReadTime( MODE_DVDROM );
CDVD_INT( cdvdStartSeek( 0, MODE_DVDROM ) );
break;
case N_CD_STOP: // CdStop
DevCon.Warning( "CdStop : %d", 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
// Assign the seek to sector based on cdvd.Param[0]-[3], and the number of sectors based on cdvd.Param[4]-[7].
cdvd.SeekToSector = *(u32*) (cdvd.Param+0);
cdvd.nSectors = *(u32*)(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;
}
CDVD_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( EmuConfig.CdvdVerboseReads )
Console.WriteLn( Color_Gray, L"CdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
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 = DoCDVDreadTrack( 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
// Assign the seek to sector based on cdvd.Param[0]-[3], and the number of sectors based on cdvd.Param[4]-[7].
cdvd.SeekToSector = *(u32*) (cdvd.Param+0);
cdvd.nSectors = *(u32*)(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;
}
CDVD_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( EmuConfig.CdvdVerboseReads )
Console.WriteLn( Color_Gray, L"CdAudioRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
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 = DoCDVDreadTrack( 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
// Assign the seek to sector based on cdvd.Param[0]-[3], and the number of sectors based on cdvd.Param[4]-[7].
cdvd.SeekToSector = *(u32*) (cdvd.Param+0);
cdvd.nSectors = *(u32*)(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
CDVD_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( EmuConfig.CdvdVerboseReads )
Console.WriteLn( Color_Gray, L"DvdRead: Reading Sector %d(%d Blocks of Size %d) at Speed=%dx",
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 = DoCDVDreadTrack( 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", 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)", arg0, arg1, arg2);
cdvdReadKey(arg0, arg1, arg2, cdvd.Key);
cdvd.KeyXor = 0x00;
cdvdSetIrq();
}
break;
case N_CD_CHG_SPDL_CTRL: // CdChgSpdlCtrl
Console.WriteLn("sceCdChgSpdlCtrl(%d)", cdvd.Param[0]);
cdvdSetIrq();
break;
default:
Console.Warning("NCMD Unknown %x", rt);
cdvdSetIrq();
break;
}
cdvd.ParamP = 0;
cdvd.ParamC = 0;
}
static __fi void cdvdWrite05(u8 rt) { // NDATAIN
CDVD_LOG("cdvdWrite05(NDataIn) %x", rt);
if (cdvd.ParamP < 32) {
cdvd.Param[cdvd.ParamP++] = rt;
cdvd.ParamC++;
}
}
static __fi void cdvdWrite06(u8 rt) { // HOWTO
CDVD_LOG("cdvdWrite06(HowTo) %x", rt);
cdvd.HowTo = rt;
}
static __fi void cdvdWrite07(u8 rt) // BREAK
{
CDVD_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.WriteLn("*PCSX2*: CDVD BREAK %x", 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_STOP;
//cdvd.nCommand = 0;
}
static __fi void cdvdWrite08(u8 rt) { // INTR_STAT
CDVD_LOG("cdvdWrite08(IntrReason) = ACK(%x)", rt);
cdvd.PwOff &= ~rt;
}
static __fi void cdvdWrite0A(u8 rt) { // STATUS
CDVD_LOG("cdvdWrite0A(Status) %x", rt);
}
static __fi void cdvdWrite0F(u8 rt) { // TYPE
CDVD_LOG("cdvdWrite0F(Type) %x", rt);
DevCon.WriteLn("*PCSX2*: CDVD TYPE %x", rt);
}
static __fi void cdvdWrite14(u8 rt) { // PS1 MODE??
u32 cycle = psxRegs.cycle;
if (rt == 0xFE)
Console.Warning("*PCSX2*: go PS1 mode DISC SPEED = FAST");
else
Console.Warning("*PCSX2*: go PS1 mode DISC SPEED = %dX", rt);
psxReset();
psxHu32(0x1f801450) = 0x8;
psxHu32(0x1f801078) = 1;
psxRegs.cycle = cycle;
}
static __fi 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;
CDVD_LOG("cdvdWrite16: SCMD %s (%x) (ParamP = %x)", sCmdName[rt], rt, cdvd.ParamP);
cdvd.sCommand = rt;
cdvd.Result[0] = 0; // assume success -- failures will overwrite this with an error code.
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);
cdvdWriteConsoleID(&cdvd.Param[1]);
break;
case 0x45: // read console ID (1:9)
SetResultSize(9);
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.Warning("*Unknown Mecacon Command param[0]=%02X", cdvd.Param[0]);
break;
}
break;
case 0x05: // CdTrayReqState (0:1) - resets the tray open detection
// Fixme: This function is believed to change some status flag
// when the Tray state (stored as "1" in cdvd.Status) is different between 2 successive calls.
// Cdvd.Status can be different than 1 here, yet we may still have to report an open status.
// Gonna have to investigate further. (rama)
//Console.Warning("CdTrayReqState. cdvd.Status = %d", cdvd.Status);
SetResultSize(1);
if (cdvd.Status == CDVD_STATUS_TRAY_OPEN)
{
//Console.Warning( "reporting Open status" );
cdvd.Result[0] = 1;
}
else
{
//Console.Warning( "reporting Close status" );
cdvd.Result[0] = 0; // old behaviour was always this
}
break;
case 0x06: // CdTrayCtrl (1:1)
SetResultSize(1);
//Console.Warning( "CdTrayCtrl, param = %d", cdvd.Param[0]);
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); //Hours
cdvd.Result[4] = 0; //Nothing
cdvd.Result[5] = itob(cdvd.RTC.day); //Day
cdvd.Result[6] = itob(cdvd.RTC.month); //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", 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", 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]) % 24;
cdvd.RTC.day = btoi(cdvd.Param[cdvd.ParamP-3]);
cdvd.RTC.month = btoi(cdvd.Param[cdvd.ParamP-2] & 0x7f);
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", 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", 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);
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;
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);
cdvdReadILinkID(&cdvd.Result[1]);
break;
case 0x13: // sceCdWriteILinkID (8:1)
SetResultSize(1);
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);
cdvdReadModelNumber(&cdvd.Result[1], cdvd.Param[0]);
break;
case 0x18: // CdWriteModelNumber (9:1) - from xcdvdman
SetResultSize(1);
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]);
cdvdReadRegionParams(&cdvd.Result[3]);//size==8
DevCon.WriteLn("REGION PARAMS = %s %s", 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);
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);
cdvdWriteMAC(&cdvd.Param[0]);
break;
case 0x3E: //[__sceCdWriteRegionParams - made up name] (15:1) [Florin: hum, i was expecting 14:1]
SetResultSize(1);
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);
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;
}
std::string zoneStr;
for (i=0; i<8; i++)
{
if (cdvd.mg_buffer[0x1C] & (1<<i)) zoneStr += mg_zones[i];
}
Console.WriteLn("[MG] ELF_size=0x%X Hdr_size=0x%X unk=0x%X flags=0x%X count=%d zones=%s",
*(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],
zoneStr.c_str()
);
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",
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", 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", rt);
break;
} // end switch
//Console.WriteLn("SCMD - 0x%x\n", rt);
cdvd.ParamP = 0;
cdvd.ParamC = 0;
}
static __fi void cdvdWrite17(u8 rt) { // SDATAIN
CDVD_LOG("cdvdWrite17(SDataIn) %x", rt);
if (cdvd.ParamP < 32) {
cdvd.Param[cdvd.ParamP++] = rt;
cdvd.ParamC++;
}
}
static __fi void cdvdWrite18(u8 rt) { // SDATAOUT
CDVD_LOG("cdvdWrite18(SDataOut) %x", rt);
Console.WriteLn("*PCSX2* SDATAOUT");
}
static __fi void cdvdWrite3A(u8 rt) { // DEC-SET
CDVD_LOG("cdvdWrite3A(DecSet) %x", rt);
cdvd.decSet = rt;
}
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.Warning("IOP Unknown 8bit write to addr 0x1f4020%x = 0x%x", key, rt);
break;
}
}