/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Mupen64plus - pif.c * * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ * * Copyright (C) 2002 Hacktarux * * * * 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 #include #ifndef __WIN32__ #include "../main/winlnxdefs.h" #else #include #endif #include "memory.h" #include "pif.h" #include "pif2.h" #include "../r4300/r4300.h" #include "../r4300/interupt.h" #include "../main/main.h" #include "../main/plugin.h" static unsigned char eeprom[0x800]; static unsigned char mempack[4][0x8000]; void check_input_sync(unsigned char *value); //#define DEBUG_PIF #ifdef DEBUG_PIF void print_pif() { int i; for (i=0; i<(64/8); i++) printf("%x %x %x %x | %x %x %x %x\n", PIF_RAMb[i*8+0], PIF_RAMb[i*8+1],PIF_RAMb[i*8+2], PIF_RAMb[i*8+3], PIF_RAMb[i*8+4], PIF_RAMb[i*8+5],PIF_RAMb[i*8+6], PIF_RAMb[i*8+7]); getchar(); } #endif void EepromCommand(BYTE *Command) { switch (Command[2]) { case 0: // check if (Command[1] != 3) { Command[1] |= 0x40; if ((Command[1] & 3) > 0) Command[3] = 0; if ((Command[1] & 3) > 1) Command[4] = ROM_SETTINGS.eeprom_16kb == 0 ? 0x80 : 0xc0; if ((Command[1] & 3) > 2) Command[5] = 0; } else { Command[3] = 0; Command[4] = ROM_SETTINGS.eeprom_16kb == 0 ? 0x80 : 0xc0; Command[5] = 0; } break; case 4: // read { char *filename; FILE *f; int i; filename = malloc(strlen(get_savespath())+ strlen(ROM_SETTINGS.goodname)+4+1); strcpy(filename, get_savespath()); strcat(filename, ROM_SETTINGS.goodname); strcat(filename, ".eep"); f = fopen(filename, "rb"); if (f) { fread(eeprom, 1, 0x800, f); fclose(f); } else for (i=0; i<0x800; i++) eeprom[i] = 0; free(filename); memcpy(&Command[4], eeprom + Command[3]*8, 8); } break; case 5: // write { char *filename; FILE *f; int i; filename = malloc(strlen(get_savespath())+ strlen(ROM_SETTINGS.goodname)+4+1); strcpy(filename, get_savespath()); strcat(filename, ROM_SETTINGS.goodname); strcat(filename, ".eep"); f = fopen(filename, "rb"); if (f) { fread(eeprom, 1, 0x800, f); fclose(f); } else for (i=0; i<0x800; i++) eeprom[i] = 0; memcpy(eeprom + Command[3]*8, &Command[4], 8); f = fopen(filename, "wb"); if (f == NULL) { printf("Warning: Couldn't open EEPROM file '%s' for writing.\n", filename); } else { fwrite(eeprom, 1, 0x800, f); fclose(f); } free(filename); } break; default: printf("unknown command in EepromCommand : %x\n", Command[2]); } } void format_mempacks() { unsigned char init[] = { 0x81,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f, 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f, 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x71,0x00,0x03, 0x00,0x03,0x00,0x03, 0x00,0x03,0x00,0x03, 0x00,0x03,0x00,0x03 }; int i,j; for (i=0; i<4; i++) { for (j=0; j<0x8000; j+=2) { mempack[i][j] = 0; mempack[i][j+1] = 0x03; } memcpy(mempack[i], init, 272); } } unsigned char mempack_crc(unsigned char *data) { int i; unsigned char CRC = 0; for (i=0; i<=0x20; i++) { int mask; for (mask = 0x80; mask >= 1; mask >>= 1) { int xor_tap = (CRC & 0x80) ? 0x85 : 0x00; CRC <<= 1; if (i != 0x20 && (data[i] & mask)) CRC |= 1; CRC ^= xor_tap; } } return CRC; } void internal_ReadController(int Control, BYTE *Command) { switch (Command[2]) { case 1: if (Controls[Control].Present) { BUTTONS Keys; getKeys(Control, &Keys); *((unsigned int *)(Command + 3)) = Keys.Value; #ifdef COMPARE_CORE check_input_sync(Command+3); #endif } break; case 2: // read controller pack if (Controls[Control].Present) { if (Controls[Control].Plugin == PLUGIN_RAW) if (controllerCommand) readController(Control, Command); } break; case 3: // write controller pack if (Controls[Control].Present) { if (Controls[Control].Plugin == PLUGIN_RAW) if (controllerCommand) readController(Control, Command); } break; } } void internal_ControllerCommand(int Control, BYTE *Command) { switch (Command[2]) { case 0x00: // check case 0xFF: if ((Command[1] & 0x80)) break; if (Controls[Control].Present) { Command[3] = 0x05; Command[4] = 0x00; switch(Controls[Control].Plugin) { 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: if (!Controls[Control].Present) Command[1] |= 0x80; break; case 0x02: // read controller pack if (Controls[Control].Present) { switch(Controls[Control].Plugin) { case PLUGIN_MEMPAK: { int address = (Command[3] << 8) | Command[4]; if (address == 0x8001) { memset(&Command[5], 0, 0x20); Command[0x25] = mempack_crc(&Command[5]); } else { address &= 0xFFE0; if (address <= 0x7FE0) { char *filename; FILE *f; filename = malloc(strlen(get_savespath())+ strlen(ROM_SETTINGS.goodname)+4+1); strcpy(filename, get_savespath()); strcat(filename, ROM_SETTINGS.goodname); strcat(filename, ".mpk"); f = fopen(filename, "rb"); if (f) { fread(mempack[0], 1, 0x8000, f); fread(mempack[1], 1, 0x8000, f); fread(mempack[2], 1, 0x8000, f); fread(mempack[3], 1, 0x8000, f); fclose(f); } else format_mempacks(); free(filename); memcpy(&Command[5], &mempack[Control][address], 0x20); } else { memset(&Command[5], 0, 0x20); } Command[0x25] = mempack_crc(&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; break; case 0x03: // write controller pack if (Controls[Control].Present) { switch(Controls[Control].Plugin) { case PLUGIN_MEMPAK: { int address = (Command[3] << 8) | Command[4]; if (address == 0x8001) Command[0x25] = mempack_crc(&Command[5]); else { address &= 0xFFE0; if (address <= 0x7FE0) { char *filename; FILE *f; filename = malloc(strlen(get_savespath())+ strlen(ROM_SETTINGS.goodname)+4+1); strcpy(filename, get_savespath()); strcat(filename, ROM_SETTINGS.goodname); strcat(filename, ".mpk"); f = fopen(filename, "rb"); if (f) { fread(mempack[0], 1, 0x8000, f); fread(mempack[1], 1, 0x8000, f); fread(mempack[2], 1, 0x8000, f); fread(mempack[3], 1, 0x8000, f); fclose(f); } else format_mempacks(); memcpy(&mempack[Control][address], &Command[5], 0x20); f = fopen(filename, "wb"); if (f == NULL) { printf("Warning: couldn't open memory pack file '%s' for writing.\n", filename); } else { fwrite(mempack[0], 1, 0x8000, f); fwrite(mempack[1], 1, 0x8000, f); fwrite(mempack[2], 1, 0x8000, f); fwrite(mempack[3], 1, 0x8000, f); } fclose(f); free(filename); } Command[0x25] = mempack_crc(&Command[5]); } } break; case PLUGIN_RAW: if (controllerCommand) controllerCommand(Control, Command); break; default: Command[0x25] = mempack_crc(&Command[5]); } } else Command[1] |= 0x80; break; } } void update_pif_write() { int i=0, channel=0; #ifdef DEBUG_PIF printf("write\n"); print_pif(); #endif if (PIF_RAMb[0x3F] > 1) { switch (PIF_RAMb[0x3F]) { case 0x02: for (i=0; i 6) i=0x40; break; case 0xFF: break; default: if (!(PIF_RAMb[i] & 0xC0)) { if (channel < 4) { if (Controls[channel].Present && Controls[channel].RawData) controllerCommand(channel, &PIF_RAMb[i]); else internal_ControllerCommand(channel, &PIF_RAMb[i]); } else if (channel == 4) EepromCommand(&PIF_RAMb[i]); else printf("channel >= 4 in update_pif_write\n"); i += PIF_RAMb[i] + (PIF_RAMb[(i+1)] & 0x3F) + 1; channel++; } else i=0x40; } i++; } //PIF_RAMb[0x3F] = 0; controllerCommand(-1, NULL); #ifdef DEBUG_PIF print_pif(); #endif } void update_pif_read() { int i=0, channel=0; #ifdef DEBUG_PIF printf("read\n"); print_pif(); #endif while (i<0x40) { switch(PIF_RAMb[i]) { case 0x00: channel++; if (channel > 6) i=0x40; break; case 0xFE: i = 0x40; break; case 0xFF: break; case 0xB4: case 0x56: case 0xB8: break; default: if (!(PIF_RAMb[i] & 0xC0)) { if (channel < 4) { if (Controls[channel].Present && Controls[channel].RawData) readController(channel, &PIF_RAMb[i]); else internal_ReadController(channel, &PIF_RAMb[i]); } i += PIF_RAMb[i] + (PIF_RAMb[(i+1)] & 0x3F) + 1; channel++; } else i=0x40; } i++; } readController(-1, NULL); #ifdef DEBUG_PIF print_pif(); #endif }