project64/Source/Project64/N64 System/C Core/Pif.cpp

478 lines
14 KiB
C++

/*
* Project 64 - A Nintendo 64 emulator.
*
* (c) Copyright 2001 zilmar (zilmar@emulation64.com) and
* Jabo (jabo@emulation64.com).
*
* pj64 homepage: www.pj64.net
*
* Permission to use, copy, modify and distribute Project64 in both binary and
* source form, for non-commercial purposes, is hereby granted without fee,
* providing that this license information and copyright notice appear with
* all copies and any derived work.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event shall the authors be held liable for any damages
* arising from the use of this software.
*
* Project64 is freeware for PERSONAL USE only. Commercial users should
* seek permission of the copyright holders first. Commercial use includes
* charging money for Project64 or software derived from Project64.
*
* The copyright holders request that bug fixes and improvements to the code
* should be forwarded to them so if they want them.
*
*/
#include <windows.h>
#include <stdio.h>
#include "main.h"
#include "cpu.h"
#include "plugin.h"
#include "Debugger.h"
void ProcessControllerCommand ( int Control, BYTE * Command);
void ReadControllerCommand (int Control, BYTE * Command);
BYTE PifRom[0x7C0];
int GetCicChipID (char * RomData) {
_int64 CRC = 0;
int count;
for (count = 0x40; count < 0x1000; count += 4) {
CRC += *(DWORD *)(RomData+count);
}
switch (CRC) {
case 0x000000D0027FDF31: return 1;
case 0x000000CFFB631223: return 1;
case 0x000000D057C85244: return 2;
case 0x000000D6497E414B: return 3;
case 0x0000011A49F60E96: return 5;
case 0x000000D6D5BE5580: return 6;
default:
return -1;
}
}
void LogControllerPakData (char * Description) {
BYTE * PIF_Ram = _MMU->PifRam();
#if (!defined(EXTERNAL_RELEASE))
int count, count2;
char HexData[100], AsciiData[100], Addon[20];
LogMessage("\t%s:",Description);
LogMessage("\t------------------------------");
for (count = 0; count < 16; count ++ ) {
if ((count % 4) == 0) {
sprintf(HexData,"\0");
sprintf(AsciiData,"\0");
}
sprintf(Addon,"%02X %02X %02X %02X",
PIF_Ram[(count << 2) + 0], PIF_Ram[(count << 2) + 1],
PIF_Ram[(count << 2) + 2], PIF_Ram[(count << 2) + 3] );
strcat(HexData,Addon);
if (((count + 1) % 4) != 0) {
sprintf(Addon,"-");
strcat(HexData,Addon);
}
Addon[0] = 0;
for (count2 = 0; count2 < 4; count2++) {
if (PIF_Ram[(count << 2) + count2] < 30) {
strcat(Addon,".");
} else {
sprintf(Addon,"%s%c",Addon,PIF_Ram[(count << 2) + count2]);
}
}
strcat(AsciiData,Addon);
if (((count + 1) % 4) == 0) {
LogMessage("\t%s %s",HexData, AsciiData);
}
}
LogMessage("");
#endif
}
#define IncreaseMaxPif2 300
int MaxPif2Cmds = 300;
unsigned __int64 * Pif2Reply[4];
BOOLEAN pif2valid = FALSE;
void LoadPIF2 () {
CPath Pif2FileName(CPath::MODULE_DIRECTORY,"pif2.dat");
FILE *pif2db = fopen (Pif2FileName, "rt");
// unsigned __int64 p1, p2, r1, r2;
char buff[255];
int cnt = 0;
Pif2Reply[0] = new unsigned __int64[MaxPif2Cmds + 1];
Pif2Reply[1] = new unsigned __int64[MaxPif2Cmds + 1];
Pif2Reply[2] = new unsigned __int64[MaxPif2Cmds + 1];
Pif2Reply[3] = new unsigned __int64[MaxPif2Cmds + 1];
if (Pif2Reply[0] == NULL || Pif2Reply[1] == NULL ||
Pif2Reply[2] == NULL || Pif2Reply[3] == NULL)
{
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
}
if (pif2db == NULL) {
Pif2Reply[0][0] = -1; Pif2Reply[1][0] = -1;
Pif2Reply[2][0] = -1; Pif2Reply[3][0] = -1;
return;
}
while (feof (pif2db) == 0) {
if (cnt == MaxPif2Cmds) {
/*MaxPif2Cmds += IncreaseMaxPif2;
Pif2Reply[0] = realloc(Pif2Reply[0],(MaxPif2Cmds + 1) * sizeof(__int64));
Pif2Reply[1] = realloc(Pif2Reply[1],(MaxPif2Cmds + 1) * sizeof(__int64));
Pif2Reply[2] = realloc(Pif2Reply[2],(MaxPif2Cmds + 1) * sizeof(__int64));
Pif2Reply[3] = realloc(Pif2Reply[3],(MaxPif2Cmds + 1) * sizeof(__int64));
if (Pif2Reply[0] == NULL || Pif2Reply[1] == NULL ||
Pif2Reply[2] == NULL || Pif2Reply[3] == NULL)
{*/
DisplayError(GS(MSG_MEM_ALLOC_ERROR));
ExitThread(0);
//}
}
fgets (buff, 255, pif2db);
if (buff[0] != ';') {
if (buff[0] != '\n') {
sscanf (buff, "0x%08X%08X, 0x%08X%08X, 0x%08X%08X, 0x%08X%08X",
((DWORD *)&Pif2Reply[0][cnt])+1, &Pif2Reply[0][cnt],
((DWORD *)&Pif2Reply[1][cnt])+1, &Pif2Reply[1][cnt],
((DWORD *)&Pif2Reply[2][cnt])+1, &Pif2Reply[2][cnt],
((DWORD *)&Pif2Reply[3][cnt])+1, &Pif2Reply[3][cnt]);
cnt++;
}
}
}
Pif2Reply[0][cnt] = Pif2Reply[1][cnt] = Pif2Reply[2][cnt] = Pif2Reply[3][cnt] = -1;
pif2valid = TRUE;
fclose (pif2db);
}
void PifRamRead (void) {
BYTE * PIF_Ram = _MMU->PifRam();
int Channel, CurPos;
Channel = 0;
CurPos = 0;
if (PIF_Ram[0x3F] == 0x2) {
int cnt = 0;
char buff[256];
if (pif2valid == FALSE)
LoadPIF2 ();
while (Pif2Reply[0][cnt] != -1) {
if (Pif2Reply[0][cnt] == *(unsigned __int64 *)&PIF_Ram[48]) {
if (Pif2Reply[1][cnt] == *(unsigned __int64 *)&PIF_Ram[56]) {
PIF_Ram[46] = PIF_Ram[47] = 0x00;
*(unsigned __int64 *)&PIF_Ram[48] = Pif2Reply[2][cnt];
*(unsigned __int64 *)&PIF_Ram[56] = Pif2Reply[3][cnt];
cnt = -1;
break;
}
}
cnt++;
}
if (cnt != -1) {
char buff2[256];
int count;
sprintf (buff, "%s :(\r\n\r\nInfo:\r\nP1=%08X%08X P2=%08X%08X\r\n", GS(MSG_PIF2_ERROR),
*(DWORD *)&PIF_Ram[52],
*(DWORD *)&PIF_Ram[48],
*(DWORD *)&PIF_Ram[60],
*(DWORD *)&PIF_Ram[56]);
for (count = 48; count < 64; count++) {
if (count % 4 == 0) {
strcat(buff,count == 48?"0x":", 0x");
}
sprintf(buff2,"%02X",PIF_Ram[count]);
strcat(buff,buff2);
}
DisplayError("%s\n\n%s",GS(MSG_PIF2_TITLE),buff);
}
/*
PIF_Ram[48] = 0x3E; PIF_Ram[49] = 0xC6; PIF_Ram[50] = 0xC0; PIF_Ram[51] = 0x4E;
PIF_Ram[52] = 0xBD; PIF_Ram[53] = 0x37; PIF_Ram[54] = 0x15; PIF_Ram[55] = 0x55;
PIF_Ram[56] = 0x5A; PIF_Ram[57] = 0x8C; PIF_Ram[58] = 0x2A; PIF_Ram[59] = 0x8C;
PIF_Ram[60] = 0xD3; PIF_Ram[61] = 0x71; PIF_Ram[62] = 0x71; PIF_Ram[63] = 0x00;
*/
CurPos = 0x40;
}
do {
switch(PIF_Ram[CurPos]) {
case 0x00:
Channel += 1;
if (Channel > 6) { CurPos = 0x40; }
break;
case 0xFE: CurPos = 0x40; break;
case 0xFF: break;
case 0xB4: case 0x56: case 0xB8: break; /* ??? */
default:
if ((PIF_Ram[CurPos] & 0xC0) == 0) {
if (Channel < 4) {
if (Controllers[Channel].Present && Controllers[Channel].RawData) {
if (ReadController) { ReadController(Channel,&PIF_Ram[CurPos]); }
} else {
ReadControllerCommand(Channel,&PIF_Ram[CurPos]);
}
}
CurPos += PIF_Ram[CurPos] + (PIF_Ram[CurPos + 1] & 0x3F) + 1;
Channel += 1;
} else {
if (ShowPifRamErrors) { DisplayError("Unknown Command in PifRamRead(%X)",PIF_Ram[CurPos]); }
CurPos = 0x40;
}
break;
}
CurPos += 1;
} while( CurPos < 0x40 );
if (ReadController) { ReadController(-1,NULL); }
}
void PifRamWrite (void) {
BYTE * PIF_Ram = _MMU->PifRam();
int Channel, CurPos;
Channel = 0;
if( PIF_Ram[0x3F] > 0x1) {
switch (PIF_Ram[0x3F]) {
case 0x08:
PIF_Ram[0x3F] = 0;
_Reg->MI_INTR_REG |= MI_INTR_SI;
_Reg->SI_STATUS_REG |= SI_STATUS_INTERRUPT;
CheckInterrupts();
break;
case 0x10:
memset(PifRom,0,0x7C0);
break;
case 0x30:
PIF_Ram[0x3F] = 0x80;
break;
case 0xC0:
memset(PIF_Ram,0,0x40);
break;
default:
if (ShowPifRamErrors) { DisplayError("Unkown PifRam control: %d",PIF_Ram[0x3F]); }
}
return;
}
for (CurPos = 0; CurPos < 0x40; CurPos++){
switch(PIF_Ram[CurPos]) {
case 0x00:
Channel += 1;
if (Channel > 6) { CurPos = 0x40; }
break;
case 0xFE: CurPos = 0x40; break;
case 0xFF: break;
case 0xB4: case 0x56: case 0xB8: break; /* ??? */
default:
if ((PIF_Ram[CurPos] & 0xC0) == 0) {
if (Channel < 4) {
if (Controllers[Channel].Present && Controllers[Channel].RawData) {
if (ControllerCommand) { ControllerCommand(Channel,&PIF_Ram[CurPos]); }
} else {
ProcessControllerCommand(Channel,&PIF_Ram[CurPos]);
}
} else if (Channel == 4) {
EepromCommand(&PIF_Ram[CurPos]);
} else {
#ifndef EXTERNAL_RELEASE
DisplayError("Command on channel 5?");
#endif
}
CurPos += PIF_Ram[CurPos] + (PIF_Ram[CurPos + 1] & 0x3F) + 1;
Channel += 1;
} else {
if (ShowPifRamErrors) { DisplayError("Unknown Command in PifRamWrite(%X)",PIF_Ram[CurPos]); }
CurPos = 0x40;
}
break;
}
}
PIF_Ram[0x3F] = 0;
if (ControllerCommand) { ControllerCommand(-1,NULL); }
}
void ProcessControllerCommand ( int Control, BYTE * Command) {
switch (Command[2]) {
case 0x00: // check
case 0xFF: // reset & check ?
if ((Command[1] & 0x80) != 0) { break; }
#ifndef EXTERNAL_RELEASE
if (Command[0] != 1) { DisplayError("What am I meant to do with this Controller Command"); }
if (Command[1] != 3) { DisplayError("What am I meant to do with this Controller Command"); }
#endif
if (Controllers[Control].Present == TRUE) {
Command[3] = 0x05;
Command[4] = 0x00;
switch ( Controllers[Control].Plugin) {
case PLUGIN_RUMBLE_PAK: Command[5] = 1; break;
case PLUGIN_MEMPAK: Command[5] = 1; break;
case PLUGIN_RAW: Command[5] = 1; break;
default: Command[5] = 0; break;
}
} else {
Command[1] |= 0x80;
}
break;
case 0x01: // read controller
#ifndef EXTERNAL_RELEASE
if (Command[0] != 1) { DisplayError("What am I meant to do with this Controller Command"); }
if (Command[1] != 4) { DisplayError("What am I meant to do with this Controller Command"); }
#endif
if (Controllers[Control].Present == FALSE) {
Command[1] |= 0x80;
}
break;
case 0x02: //read from controller pack
#ifndef EXTERNAL_RELEASE
if (LogOptions.LogControllerPak) { LogControllerPakData("Read: Before Gettting Results"); }
if (Command[0] != 3) { DisplayError("What am I meant to do with this Controller Command"); }
if (Command[1] != 33) { DisplayError("What am I meant to do with this Controller Command"); }
#endif
if (Controllers[Control].Present == TRUE) {
DWORD address = ((Command[3] << 8) | Command[4]);
switch (Controllers[Control].Plugin) {
case PLUGIN_RUMBLE_PAK:
memset(&Command[5], (address >= 0x8000 && address < 0x9000) ? 0x80 : 0x00, 0x20);
Command[0x25] = Mempacks_CalulateCrc(&Command[5]);
break;
case PLUGIN_MEMPAK: ReadFromMempak(Control, address, &Command[5]); break;
case PLUGIN_RAW: if (ControllerCommand) { ControllerCommand(Control, Command); } break;
default:
memset(&Command[5], 0, 0x20);
Command[0x25] = 0;
}
} else {
Command[1] |= 0x80;
}
#ifndef EXTERNAL_RELEASE
if (LogOptions.LogControllerPak) { LogControllerPakData("Read: After Gettting Results"); }
#endif
break;
case 0x03: //write controller pak
#ifndef EXTERNAL_RELEASE
if (LogOptions.LogControllerPak) { LogControllerPakData("Write: Before Processing"); }
if (Command[0] != 35) { DisplayError("What am I meant to do with this Controller Command"); }
if (Command[1] != 1) { DisplayError("What am I meant to do with this Controller Command"); }
#endif
if (Controllers[Control].Present == TRUE) {
DWORD address = ((Command[3] << 8) | Command[4]);
switch (Controllers[Control].Plugin) {
case PLUGIN_MEMPAK: WriteToMempak(Control, address, &Command[5]); break;
case PLUGIN_RAW: if (ControllerCommand) { ControllerCommand(Control, Command); } break;
case PLUGIN_RUMBLE_PAK:
if ((address & 0xFFE0) == 0xC000 && RumbleCommand != NULL) {
RumbleCommand(Control, *(BOOL *)(&Command[5]));
}
default:
Command[0x25] = Mempacks_CalulateCrc(&Command[5]);
}
} else {
Command[1] |= 0x80;
}
#ifndef EXTERNAL_RELEASE
if (LogOptions.LogControllerPak) { LogControllerPakData("Write: After Processing"); }
#endif
break;
default:
if (ShowPifRamErrors) { DisplayError("Unknown ControllerCommand %d",Command[2]); }
}
}
void ReadControllerCommand (int Control, BYTE * Command) {
switch (Command[2]) {
case 0x01: // read controller
if (Controllers[Control].Present == TRUE) {
#ifndef EXTERNAL_RELEASE
if (Command[0] != 1) { DisplayError("What am I meant to do with this Controller Command"); }
if (Command[1] != 4) { DisplayError("What am I meant to do with this Controller Command"); }
#endif
if (GetKeys) {
BUTTONS Keys;
GetKeys(Control,&Keys);
*(DWORD *)&Command[3] = Keys.Value;
} else {
*(DWORD *)&Command[3] = 0;
}
}
break;
case 0x02: //read from controller pack
if (Controllers[Control].Present == TRUE) {
switch (Controllers[Control].Plugin) {
case PLUGIN_RAW: if (ReadController) { ReadController(Control, Command); } break;
}
}
break;
case 0x03: //write controller pak
if (Controllers[Control].Present == TRUE) {
switch (Controllers[Control].Plugin) {
case PLUGIN_RAW: if (ReadController) { ReadController(Control, Command); } break;
}
}
break;
}
}
int LoadPifRom(int country) {
char path_buffer[_MAX_PATH], drive[_MAX_DRIVE] ,dir[_MAX_DIR];
char fname[_MAX_FNAME],ext[_MAX_EXT], PifRomName[255];
HANDLE hPifFile;
DWORD dwRead;
GetModuleFileName(NULL,path_buffer,sizeof(path_buffer));
_splitpath( path_buffer, drive, dir, fname, ext );
switch (country) {
case 0x44: //Germany
case 0x46: //french
case 0x49: //Italian
case 0x50: //Europe
case 0x53: //Spanish
case 0x55: //Australia
case 0x58: // X (PAL)
case 0x59: // X (PAL)
sprintf(PifRomName,"%s%sPifrom\\pifpal.raw",drive,dir);
break;
case 0: //None
case 0x37: // 7 (Beta)
case 0x41: // ????
case 0x45: //USA
case 0x4A: //Japan
sprintf(PifRomName,"%s%sPifrom\\pifntsc.raw",drive,dir);
break;
default:
DisplayError(GS(MSG_UNKNOWN_COUNTRY));
}
hPifFile = CreateFile(PifRomName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
if (hPifFile == INVALID_HANDLE_VALUE) {
memset(PifRom,0,0x7C0);
return FALSE;
}
SetFilePointer(hPifFile,0,NULL,FILE_BEGIN);
ReadFile(hPifFile,PifRom,0x7C0,&dwRead,NULL);
CloseHandle( hPifFile );
return TRUE;
}