ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / mupen64plus-core / src / memory / pif.c
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
42 static unsigned char eeprom[0x800];
43 static unsigned char mempack[4][0x8000];
44
45 static char *get_eeprom_path(void)
46 {
47     return formatstr("%s%s.eep", get_savesrampath(), ROM_SETTINGS.goodname);
48 }
49
50 static void eeprom_format(void)
51 {
52     memset(eeprom, 0, sizeof(eeprom));
53 }
54
55 static 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
74 static 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
92 static char *get_mempack_path(void)
93 {
94     return formatstr("%s%s.mpk", get_savesrampath(), ROM_SETTINGS.goodname);
95 }
96
97 static 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
131 static 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
150 static 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
170 void 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
180 static unsigned char byte2bcd(int n)
181 {
182     n %= 100;
183     return ((n / 10) << 4) | (n % 10);
184 }
185
186 static 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
280 static 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
298 static 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
341 static 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
475 void 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);
495             PIF_RAMb[46] = 0;
496             PIF_RAMb[47] = 0;
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
553 void 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