ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / mupen64plus-core / src / memory / pif.c
CommitLineData
451ab91e 1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - pif.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2002 Hacktarux *
5 * *
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. *
10 * *
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. *
15 * *
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 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22#include <stdio.h>
23#include <string.h>
24#include <stdlib.h>
25#include <time.h>
26
27#include "memory.h"
28#include "pif.h"
29#include "n64_cic_nus_6105.h"
30
31#include "r4300/r4300.h"
32#include "r4300/interupt.h"
33
34#include "api/m64p_types.h"
35#include "api/callbacks.h"
36#include "api/debugger.h"
37#include "main/main.h"
38#include "main/rom.h"
39#include "main/util.h"
40#include "plugin/plugin.h"
41
42static unsigned char eeprom[0x800];
43static unsigned char mempack[4][0x8000];
44
45static char *get_eeprom_path(void)
46{
47 return formatstr("%s%s.eep", get_savesrampath(), ROM_SETTINGS.goodname);
48}
49
50static void eeprom_format(void)
51{
52 memset(eeprom, 0, sizeof(eeprom));
53}
54
55static void eeprom_read_file(void)
56{
57 char *filename = get_eeprom_path();
58
59 switch (read_from_file(filename, eeprom, sizeof(eeprom)))
60 {
61 case file_open_error:
62 DebugMessage(M64MSG_VERBOSE, "couldn't open eeprom file '%s' for reading", filename);
63 eeprom_format();
64 break;
65 case file_read_error:
66 DebugMessage(M64MSG_WARNING, "fread() failed for 2kb eeprom file '%s'", filename);
67 break;
68 default: break;
69 }
70
71 free(filename);
72}
73
74static void eeprom_write_file(void)
75{
76 char *filename = get_eeprom_path();
77
78 switch (write_to_file(filename, eeprom, sizeof(eeprom)))
79 {
80 case file_open_error:
81 DebugMessage(M64MSG_WARNING, "couldn't open eeprom file '%s' for writing", filename);
82 break;
83 case file_write_error:
84 DebugMessage(M64MSG_WARNING, "fwrite() failed for 2kb eeprom file '%s'", filename);
85 break;
86 default: break;
87 }
88
89 free(filename);
90}
91
92static char *get_mempack_path(void)
93{
94 return formatstr("%s%s.mpk", get_savesrampath(), ROM_SETTINGS.goodname);
95}
96
97static void mempack_format(void)
98{
99 unsigned char init[] =
100 {
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
118 };
119 int i,j;
120 for (i=0; i<4; i++)
121 {
122 for (j=0; j<0x8000; j+=2)
123 {
124 mempack[i][j] = 0;
125 mempack[i][j+1] = 0x03;
126 }
127 memcpy(mempack[i], init, 272);
128 }
129}
130
131static void mempack_read_file(void)
132{
133 char *filename = get_mempack_path();
134
135 switch (read_from_file(filename, mempack, sizeof(mempack)))
136 {
137 case file_open_error:
138 DebugMessage(M64MSG_VERBOSE, "couldn't open memory pack file '%s' for reading", filename);
139 mempack_format();
140 break;
141 case file_read_error:
142 DebugMessage(M64MSG_WARNING, "fread() failed for 128kb mempack file '%s'", filename);
143 break;
144 default: break;
145 }
146
147 free(filename);
148}
149
150static void mempack_write_file(void)
151{
152 char *filename = get_mempack_path();
153
154 switch (write_to_file(filename, mempack, sizeof(mempack)))
155 {
156 case file_open_error:
157 DebugMessage(M64MSG_WARNING, "couldn't open memory pack file '%s' for writing", filename);
158 break;
159 case file_write_error:
160 DebugMessage(M64MSG_WARNING, "fwrite() failed for 128kb mempack file '%s'", filename);
161 break;
162 default: break;
163 }
164
165 free(filename);
166}
167
168//#define DEBUG_PIF
169#ifdef DEBUG_PIF
170void print_pif(void)
171{
172 int i;
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]);
177}
178#endif
179
180static unsigned char byte2bcd(int n)
181{
182 n %= 100;
183 return ((n / 10) << 4) | (n % 10);
184}
185
186static void EepromCommand(unsigned char *Command)
187{
188 time_t curtime_time;
189 struct tm *curtime;
190
191 switch (Command[2])
192 {
193 case 0: // check
194#ifdef DEBUG_PIF
195 DebugMessage(M64MSG_INFO, "EepromCommand() check size");
196#endif
197 if (Command[1] != 3)
198 {
199 Command[1] |= 0x40;
200 if ((Command[1] & 3) > 0)
201 Command[3] = 0;
202 if ((Command[1] & 3) > 1)
203 Command[4] = (ROM_SETTINGS.savetype != EEPROM_16KB) ? 0x80 : 0xc0;
204 if ((Command[1] & 3) > 2)
205 Command[5] = 0;
206 }
207 else
208 {
209 Command[3] = 0;
210 Command[4] = (ROM_SETTINGS.savetype != EEPROM_16KB) ? 0x80 : 0xc0;
211 Command[5] = 0;
212 }
213 break;
214 case 4: // read
215 {
216#ifdef DEBUG_PIF
217 DebugMessage(M64MSG_INFO, "EepromCommand() read 8-byte block %i", Command[3]);
218#endif
219 eeprom_read_file();
220 memcpy(&Command[4], eeprom + Command[3]*8, 8);
221 }
222 break;
223 case 5: // write
224 {
225#ifdef DEBUG_PIF
226 DebugMessage(M64MSG_INFO, "EepromCommand() write 8-byte block %i", Command[3]);
227#endif
228 eeprom_read_file();
229 memcpy(eeprom + Command[3]*8, &Command[4], 8);
230 eeprom_write_file();
231 }
232 break;
233 case 6:
234#ifdef DEBUG_PIF
235 DebugMessage(M64MSG_INFO, "EepromCommand() RTC status query");
236#endif
237 // RTCstatus query
238 Command[3] = 0x00;
239 Command[4] = 0x10;
240 Command[5] = 0x00;
241 break;
242 case 7:
243#ifdef DEBUG_PIF
244 DebugMessage(M64MSG_INFO, "EepromCommand() read RTC block %i", Command[3]);
245#endif
246 // read RTC block
247 switch (Command[3]) { // block number
248 case 0:
249 Command[4] = 0x00;
250 Command[5] = 0x02;
251 Command[12] = 0x00;
252 break;
253 case 1:
254 DebugMessage(M64MSG_ERROR, "RTC command in EepromCommand(): read block %d", Command[2]);
255 break;
256 case 2:
257 time(&curtime_time);
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
268 break;
269 }
270 break;
271 case 8:
272 // write RTC block
273 DebugMessage(M64MSG_ERROR, "RTC write in EepromCommand(): %d not yet implemented", Command[2]);
274 break;
275 default:
276 DebugMessage(M64MSG_ERROR, "unknown command in EepromCommand(): %x", Command[2]);
277 }
278}
279
280static unsigned char mempack_crc(unsigned char *data)
281{
282 int i;
283 unsigned char CRC = 0;
284 for (i=0; i<=0x20; i++)
285 {
286 int mask;
287 for (mask = 0x80; mask >= 1; mask >>= 1)
288 {
289 int xor_tap = (CRC & 0x80) ? 0x85 : 0x00;
290 CRC <<= 1;
291 if (i != 0x20 && (data[i] & mask)) CRC |= 1;
292 CRC ^= xor_tap;
293 }
294 }
295 return CRC;
296}
297
298static void internal_ReadController(int Control, unsigned char *Command)
299{
300 switch (Command[2])
301 {
302 case 1:
303#ifdef DEBUG_PIF
304 DebugMessage(M64MSG_INFO, "internal_ReadController() Channel %i Command 1 read buttons", Control);
305#endif
306 if (Controls[Control].Present)
307 {
308 BUTTONS Keys;
309 input.getKeys(Control, &Keys);
310 *((unsigned int *)(Command + 3)) = Keys.Value;
311#ifdef COMPARE_CORE
312 CoreCompareDataSync(4, Command+3);
313#endif
314 }
315 break;
316 case 2: // read controller pack
317#ifdef DEBUG_PIF
318 DebugMessage(M64MSG_INFO, "internal_ReadController() Channel %i Command 2 read controller pack (in Input plugin)", Control);
319#endif
320 if (Controls[Control].Present)
321 {
322 if (Controls[Control].Plugin == PLUGIN_RAW)
323 if (input.readController)
324 input.readController(Control, Command);
325 }
326 break;
327 case 3: // write controller pack
328#ifdef DEBUG_PIF
329 DebugMessage(M64MSG_INFO, "internal_ReadController() Channel %i Command 3 write controller pack (in Input plugin)", Control);
330#endif
331 if (Controls[Control].Present)
332 {
333 if (Controls[Control].Plugin == PLUGIN_RAW)
334 if (input.readController)
335 input.readController(Control, Command);
336 }
337 break;
338 }
339}
340
341static void internal_ControllerCommand(int Control, unsigned char *Command)
342{
343 switch (Command[2])
344 {
345 case 0x00: // read status
346 case 0xFF: // reset
347 if ((Command[1] & 0x80))
348 break;
349#ifdef DEBUG_PIF
350 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command %02x check pack present", Control, Command[2]);
351#endif
352 if (Controls[Control].Present)
353 {
354 Command[3] = 0x05;
355 Command[4] = 0x00;
356 switch (Controls[Control].Plugin)
357 {
358 case PLUGIN_MEMPAK:
359 Command[5] = 1;
360 break;
361 case PLUGIN_RAW:
362 Command[5] = 1;
363 break;
364 default:
365 Command[5] = 0;
366 break;
367 }
368 }
369 else
370 Command[1] |= 0x80;
371 break;
372 case 0x01:
373#ifdef DEBUG_PIF
374 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 1 check controller present", Control);
375#endif
376 if (!Controls[Control].Present)
377 Command[1] |= 0x80;
378 break;
379 case 0x02: // read controller pack
380 if (Controls[Control].Present)
381 {
382 switch (Controls[Control].Plugin)
383 {
384 case PLUGIN_MEMPAK:
385 {
386 int address = (Command[3] << 8) | Command[4];
387#ifdef DEBUG_PIF
388 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 2 read mempack address %04x", Control, address);
389#endif
390 if (address == 0x8001)
391 {
392 memset(&Command[5], 0, 0x20);
393 Command[0x25] = mempack_crc(&Command[5]);
394 }
395 else
396 {
397 address &= 0xFFE0;
398 if (address <= 0x7FE0)
399 {
400 mempack_read_file();
401 memcpy(&Command[5], &mempack[Control][address], 0x20);
402 }
403 else
404 {
405 memset(&Command[5], 0, 0x20);
406 }
407 Command[0x25] = mempack_crc(&Command[5]);
408 }
409 }
410 break;
411 case PLUGIN_RAW:
412#ifdef DEBUG_PIF
413 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 2 controllerCommand (in Input plugin)", Control);
414#endif
415 if (input.controllerCommand)
416 input.controllerCommand(Control, Command);
417 break;
418 default:
419#ifdef DEBUG_PIF
420 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 2 (no pack plugged in)", Control);
421#endif
422 memset(&Command[5], 0, 0x20);
423 Command[0x25] = 0;
424 }
425 }
426 else
427 Command[1] |= 0x80;
428 break;
429 case 0x03: // write controller pack
430 if (Controls[Control].Present)
431 {
432 switch (Controls[Control].Plugin)
433 {
434 case PLUGIN_MEMPAK:
435 {
436 int address = (Command[3] << 8) | Command[4];
437#ifdef DEBUG_PIF
438 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 3 write mempack address %04x", Control, address);
439#endif
440 if (address == 0x8001)
441 Command[0x25] = mempack_crc(&Command[5]);
442 else
443 {
444 address &= 0xFFE0;
445 if (address <= 0x7FE0)
446 {
447 mempack_read_file();
448 memcpy(&mempack[Control][address], &Command[5], 0x20);
449 mempack_write_file();
450 }
451 Command[0x25] = mempack_crc(&Command[5]);
452 }
453 }
454 break;
455 case PLUGIN_RAW:
456#ifdef DEBUG_PIF
457 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 3 controllerCommand (in Input plugin)", Control);
458#endif
459 if (input.controllerCommand)
460 input.controllerCommand(Control, Command);
461 break;
462 default:
463#ifdef DEBUG_PIF
464 DebugMessage(M64MSG_INFO, "internal_ControllerCommand() Channel %i Command 3 (no pack plugged in)", Control);
465#endif
466 Command[0x25] = mempack_crc(&Command[5]);
467 }
468 }
469 else
470 Command[1] |= 0x80;
471 break;
472 }
473}
474
475void update_pif_write(void)
476{
477 char challenge[30], response[30];
478 int i=0, channel=0;
479 if (PIF_RAMb[0x3F] > 1)
480 {
481 switch (PIF_RAMb[0x3F])
482 {
483 case 0x02:
484#ifdef DEBUG_PIF
485 DebugMessage(M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 2 - CIC challenge");
486#endif
487 // format the 'challenge' message into 30 nibbles for X-Scale's CIC code
488 for (i = 0; i < 15; i++)
489 {
490 challenge[i*2] = (PIF_RAMb[48+i] >> 4) & 0x0f;
491 challenge[i*2+1] = PIF_RAMb[48+i] & 0x0f;
492 }
493 // calculate the proper response for the given challenge (X-Scale's algorithm)
494 n64_cic_nus_6105(challenge, response, CHL_LEN - 2);
2d262872 495 PIF_RAMb[46] = 0;
496 PIF_RAMb[47] = 0;
451ab91e 497 // re-format the 'response' into a byte stream
498 for (i = 0; i < 15; i++)
499 {
500 PIF_RAMb[48+i] = (response[i*2] << 4) + response[i*2+1];
501 }
502 // the last byte (2 nibbles) is always 0
503 PIF_RAMb[63] = 0;
504 break;
505 case 0x08:
506#ifdef DEBUG_PIF
507 DebugMessage(M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 8");
508#endif
509 PIF_RAMb[0x3F] = 0;
510 break;
511 default:
512 DebugMessage(M64MSG_ERROR, "error in update_pif_write(): %x", PIF_RAMb[0x3F]);
513 }
514 return;
515 }
516 while (i<0x40)
517 {
518 switch (PIF_RAMb[i])
519 {
520 case 0x00:
521 channel++;
522 if (channel > 6) i=0x40;
523 break;
524 case 0xFF:
525 break;
526 default:
527 if (!(PIF_RAMb[i] & 0xC0))
528 {
529 if (channel < 4)
530 {
531 if (Controls[channel].Present &&
532 Controls[channel].RawData)
533 input.controllerCommand(channel, &PIF_RAMb[i]);
534 else
535 internal_ControllerCommand(channel, &PIF_RAMb[i]);
536 }
537 else if (channel == 4)
538 EepromCommand(&PIF_RAMb[i]);
539 else
540 DebugMessage(M64MSG_ERROR, "channel >= 4 in update_pif_write");
541 i += PIF_RAMb[i] + (PIF_RAMb[(i+1)] & 0x3F) + 1;
542 channel++;
543 }
544 else
545 i=0x40;
546 }
547 i++;
548 }
549 //PIF_RAMb[0x3F] = 0;
550 input.controllerCommand(-1, NULL);
551}
552
553void update_pif_read(void)
554{
555 int i=0, channel=0;
556 while (i<0x40)
557 {
558 switch (PIF_RAMb[i])
559 {
560 case 0x00:
561 channel++;
562 if (channel > 6) i=0x40;
563 break;
564 case 0xFE:
565 i = 0x40;
566 break;
567 case 0xFF:
568 break;
569 case 0xB4:
570 case 0x56:
571 case 0xB8:
572 break;
573 default:
574 if (!(PIF_RAMb[i] & 0xC0))
575 {
576 if (channel < 4)
577 {
578 if (Controls[channel].Present &&
579 Controls[channel].RawData)
580 input.readController(channel, &PIF_RAMb[i]);
581 else
582 internal_ReadController(channel, &PIF_RAMb[i]);
583 }
584 i += PIF_RAMb[i] + (PIF_RAMb[(i+1)] & 0x3F) + 1;
585 channel++;
586 }
587 else
588 i=0x40;
589 }
590 i++;
591 }
592 input.readController(-1, NULL);
593}
594