1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - pif.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2002 Hacktarux *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
29 #include "n64_cic_nus_6105.h"
31 #include "r4300/r4300.h"
32 #include "r4300/interupt.h"
34 #include "api/m64p_types.h"
35 #include "api/callbacks.h"
36 #include "api/debugger.h"
37 #include "main/main.h"
39 #include "main/util.h"
40 #include "plugin/plugin.h"
42 static unsigned char eeprom[0x800];
43 static unsigned char mempack[4][0x8000];
45 static char *get_eeprom_path(void)
47 return formatstr("%s%s.eep", get_savesrampath(), ROM_SETTINGS.goodname);
50 static void eeprom_format(void)
52 memset(eeprom, 0, sizeof(eeprom));
55 static void eeprom_read_file(void)
57 char *filename = get_eeprom_path();
59 switch (read_from_file(filename, eeprom, sizeof(eeprom)))
62 DebugMessage(M64MSG_VERBOSE, "couldn't open eeprom file '%s' for reading", filename);
66 DebugMessage(M64MSG_WARNING, "fread() failed for 2kb eeprom file '%s'", filename);
74 static void eeprom_write_file(void)
76 char *filename = get_eeprom_path();
78 switch (write_to_file(filename, eeprom, sizeof(eeprom)))
81 DebugMessage(M64MSG_WARNING, "couldn't open eeprom file '%s' for writing", filename);
83 case file_write_error:
84 DebugMessage(M64MSG_WARNING, "fwrite() failed for 2kb eeprom file '%s'", filename);
92 static char *get_mempack_path(void)
94 return formatstr("%s%s.mpk", get_savesrampath(), ROM_SETTINGS.goodname);
97 static void mempack_format(void)
99 unsigned char init[] =
101 0x81,0x01,0x02,0x03, 0x04,0x05,0x06,0x07, 0x08,0x09,0x0a,0x0b, 0x0c,0x0d,0x0e,0x0f,
102 0x10,0x11,0x12,0x13, 0x14,0x15,0x16,0x17, 0x18,0x19,0x1a,0x1b, 0x1c,0x1d,0x1e,0x1f,
103 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
104 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd,
105 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
106 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
107 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
108 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd,
109 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
110 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd,
111 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
112 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
113 0xff,0xff,0xff,0xff, 0x05,0x1a,0x5f,0x13, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
114 0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff, 0xff,0xff,0x01,0xff, 0x66,0x25,0x99,0xcd,
115 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
116 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,
117 0x00,0x71,0x00,0x03, 0x00,0x03,0x00,0x03, 0x00,0x03,0x00,0x03, 0x00,0x03,0x00,0x03
122 for (j=0; j<0x8000; j+=2)
125 mempack[i][j+1] = 0x03;
127 memcpy(mempack[i], init, 272);
131 static void mempack_read_file(void)
133 char *filename = get_mempack_path();
135 switch (read_from_file(filename, mempack, sizeof(mempack)))
137 case file_open_error:
138 DebugMessage(M64MSG_VERBOSE, "couldn't open memory pack file '%s' for reading", filename);
141 case file_read_error:
142 DebugMessage(M64MSG_WARNING, "fread() failed for 128kb mempack file '%s'", filename);
150 static void mempack_write_file(void)
152 char *filename = get_mempack_path();
154 switch (write_to_file(filename, mempack, sizeof(mempack)))
156 case file_open_error:
157 DebugMessage(M64MSG_WARNING, "couldn't open memory pack file '%s' for writing", filename);
159 case file_write_error:
160 DebugMessage(M64MSG_WARNING, "fwrite() failed for 128kb mempack file '%s'", filename);
173 for (i=0; i<(64/8); i++)
174 DebugMessage(M64MSG_INFO, "%x %x %x %x | %x %x %x %x",
175 PIF_RAMb[i*8+0], PIF_RAMb[i*8+1],PIF_RAMb[i*8+2], PIF_RAMb[i*8+3],
176 PIF_RAMb[i*8+4], PIF_RAMb[i*8+5],PIF_RAMb[i*8+6], PIF_RAMb[i*8+7]);
180 static unsigned char byte2bcd(int n)
183 return ((n / 10) << 4) | (n % 10);
186 static void EepromCommand(unsigned char *Command)
195 DebugMessage(M64MSG_INFO, "EepromCommand() check size");
200 if ((Command[1] & 3) > 0)
202 if ((Command[1] & 3) > 1)
203 Command[4] = (ROM_SETTINGS.savetype != EEPROM_16KB) ? 0x80 : 0xc0;
204 if ((Command[1] & 3) > 2)
210 Command[4] = (ROM_SETTINGS.savetype != EEPROM_16KB) ? 0x80 : 0xc0;
217 DebugMessage(M64MSG_INFO, "EepromCommand() read 8-byte block %i", Command[3]);
220 memcpy(&Command[4], eeprom + Command[3]*8, 8);
226 DebugMessage(M64MSG_INFO, "EepromCommand() write 8-byte block %i", Command[3]);
229 memcpy(eeprom + Command[3]*8, &Command[4], 8);
235 DebugMessage(M64MSG_INFO, "EepromCommand() RTC status query");
244 DebugMessage(M64MSG_INFO, "EepromCommand() read RTC block %i", Command[3]);
247 switch (Command[3]) { // block number
254 DebugMessage(M64MSG_ERROR, "RTC command in EepromCommand(): read block %d", Command[2]);
258 curtime = localtime(&curtime_time);
259 Command[4] = byte2bcd(curtime->tm_sec);
260 Command[5] = byte2bcd(curtime->tm_min);
261 Command[6] = 0x80 + byte2bcd(curtime->tm_hour);
262 Command[7] = byte2bcd(curtime->tm_mday);
263 Command[8] = byte2bcd(curtime->tm_wday);
264 Command[9] = byte2bcd(curtime->tm_mon + 1);
265 Command[10] = byte2bcd(curtime->tm_year);
266 Command[11] = byte2bcd(curtime->tm_year / 100);
267 Command[12] = 0x00; // status
273 DebugMessage(M64MSG_ERROR, "RTC write in EepromCommand(): %d not yet implemented", Command[2]);
276 DebugMessage(M64MSG_ERROR, "unknown command in EepromCommand(): %x", Command[2]);
280 static unsigned char mempack_crc(unsigned char *data)
283 unsigned char CRC = 0;
284 for (i=0; i<=0x20; i++)
287 for (mask = 0x80; mask >= 1; mask >>= 1)
289 int xor_tap = (CRC & 0x80) ? 0x85 : 0x00;
291 if (i != 0x20 && (data[i] & mask)) CRC |= 1;
298 static void internal_ReadController(int Control, unsigned char *Command)
304 DebugMessage(M64MSG_INFO, "internal_ReadController() Channel %i Command 1 read buttons", Control);
306 if (Controls[Control].Present)
309 input.getKeys(Control, &Keys);
310 *((unsigned int *)(Command + 3)) = Keys.Value;
312 CoreCompareDataSync(4, Command+3);
316 case 2: // read controller pack
318 DebugMessage(M64MSG_INFO, "internal_ReadController() Channel %i Command 2 read controller pack (in Input plugin)", Control);
320 if (Controls[Control].Present)
322 if (Controls[Control].Plugin == PLUGIN_RAW)
323 if (input.readController)
324 input.readController(Control, Command);
327 case 3: // write controller pack
329 DebugMessage(M64MSG_INFO, "internal_ReadController() Channel %i Command 3 write controller pack (in Input plugin)", Control);
331 if (Controls[Control].Present)
333 if (Controls[Control].Plugin == PLUGIN_RAW)
334 if (input.readController)
335 input.readController(Control, Command);
341 static void internal_ControllerCommand(int Control, unsigned char *Command)
345 case 0x00: // read status
347 if ((Command[1] & 0x80))
350 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command %02x check pack present", Control, Command[2]);
352 if (Controls[Control].Present)
356 switch (Controls[Control].Plugin)
374 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 1 check controller present", Control);
376 if (!Controls[Control].Present)
379 case 0x02: // read controller pack
380 if (Controls[Control].Present)
382 switch (Controls[Control].Plugin)
386 int address = (Command[3] << 8) | Command[4];
388 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 2 read mempack address %04x", Control, address);
390 if (address == 0x8001)
392 memset(&Command[5], 0, 0x20);
393 Command[0x25] = mempack_crc(&Command[5]);
398 if (address <= 0x7FE0)
401 memcpy(&Command[5], &mempack[Control][address], 0x20);
405 memset(&Command[5], 0, 0x20);
407 Command[0x25] = mempack_crc(&Command[5]);
413 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 2 controllerCommand (in Input plugin)", Control);
415 if (input.controllerCommand)
416 input.controllerCommand(Control, Command);
420 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 2 (no pack plugged in)", Control);
422 memset(&Command[5], 0, 0x20);
429 case 0x03: // write controller pack
430 if (Controls[Control].Present)
432 switch (Controls[Control].Plugin)
436 int address = (Command[3] << 8) | Command[4];
438 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 3 write mempack address %04x", Control, address);
440 if (address == 0x8001)
441 Command[0x25] = mempack_crc(&Command[5]);
445 if (address <= 0x7FE0)
448 memcpy(&mempack[Control][address], &Command[5], 0x20);
449 mempack_write_file();
451 Command[0x25] = mempack_crc(&Command[5]);
457 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 3 controllerCommand (in Input plugin)", Control);
459 if (input.controllerCommand)
460 input.controllerCommand(Control, Command);
464 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 3 (no pack plugged in)", Control);
466 Command[0x25] = mempack_crc(&Command[5]);
475 void update_pif_write(void)
477 char challenge[30], response[30];
479 if (PIF_RAMb[0x3F] > 1)
481 switch (PIF_RAMb[0x3F])
485 DebugMessage(M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 2 - CIC challenge");
487 // format the 'challenge' message into 30 nibbles for X-Scale's CIC code
488 for (i = 0; i < 15; i++)
490 challenge[i*2] = (PIF_RAMb[48+i] >> 4) & 0x0f;
491 challenge[i*2+1] = PIF_RAMb[48+i] & 0x0f;
493 // calculate the proper response for the given challenge (X-Scale's algorithm)
494 n64_cic_nus_6105(challenge, response, CHL_LEN - 2);
497 // re-format the 'response' into a byte stream
498 for (i = 0; i < 15; i++)
500 PIF_RAMb[48+i] = (response[i*2] << 4) + response[i*2+1];
502 // the last byte (2 nibbles) is always 0
507 DebugMessage(M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 8");
512 DebugMessage(M64MSG_ERROR, "error in update_pif_write(): %x", PIF_RAMb[0x3F]);
522 if (channel > 6) i=0x40;
527 if (!(PIF_RAMb[i] & 0xC0))
531 if (Controls[channel].Present &&
532 Controls[channel].RawData)
533 input.controllerCommand(channel, &PIF_RAMb[i]);
535 internal_ControllerCommand(channel, &PIF_RAMb[i]);
537 else if (channel == 4)
538 EepromCommand(&PIF_RAMb[i]);
540 DebugMessage(M64MSG_ERROR, "channel >= 4 in update_pif_write");
541 i += PIF_RAMb[i] + (PIF_RAMb[(i+1)] & 0x3F) + 1;
549 //PIF_RAMb[0x3F] = 0;
550 input.controllerCommand(-1, NULL);
553 void update_pif_read(void)
562 if (channel > 6) i=0x40;
574 if (!(PIF_RAMb[i] & 0xC0))
578 if (Controls[channel].Present &&
579 Controls[channel].RawData)
580 input.readController(channel, &PIF_RAMb[i]);
582 internal_ReadController(channel, &PIF_RAMb[i]);
584 i += PIF_RAMb[i] + (PIF_RAMb[(i+1)] & 0x3F) + 1;
592 input.readController(-1, NULL);