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 "pif.h"
23 #include "n64_cic_nus_6105.h"
24 #include "game_controller.h"
25 #include "si_controller.h"
26 
27 #include "../api/m64p_types.h"
28 #include "../api/callbacks.h"
29 #include "../memory/memory.h"
30 #include "../plugin/plugin.h"
31 #include "r4300/r4300_core.h"
32 
33 #include "../plugin/emulate_game_controller_via_input_plugin.h"
34 #include "../plugin/rumble_via_input_plugin.h"
35 
36 #include <string.h>
37 
38 //#define DEBUG_PIF
39 #ifdef DEBUG_PIF
print_pif(struct pif * pif)40 void print_pif(struct pif* pif)
41 {
42    int i;
43    for (i=0; i<(64/8); i++)
44       DebugMessage(M64MSG_INFO, "%x %x %x %x | %x %x %x %x",
45             pif->ram[i*8+0], pif->ram[i*8+1], pif->ram[i*8+2], pif->ram[i*8+3],
46             pif->ram[i*8+4], pif->ram[i*8+5], pif->ram[i*8+6], pif->ram[i*8+7]);
47 }
48 #endif
49 
process_cart_command(struct pif * pif,uint8_t * cmd)50 static void process_cart_command(struct pif* pif, uint8_t* cmd)
51 {
52    switch (cmd[2])
53    {
54       case PIF_CMD_STATUS: eeprom_status_command(&pif->eeprom, cmd); break;
55       case PIF_CMD_EEPROM_READ: eeprom_read_command(&pif->eeprom, cmd); break;
56       case PIF_CMD_EEPROM_WRITE: eeprom_write_command(&pif->eeprom, cmd); break;
57       case PIF_CMD_AF_RTC_STATUS: af_rtc_status_command(&pif->af_rtc, cmd); break;
58       case PIF_CMD_AF_RTC_READ: af_rtc_read_command(&pif->af_rtc, cmd); break;
59       case PIF_CMD_AF_RTC_WRITE: af_rtc_write_command(&pif->af_rtc, cmd); break;
60       default:
61          DebugMessage(M64MSG_ERROR, "unknown PIF command: %02x", cmd[2]);
62    }
63 }
64 
game_controller_dummy_save(void * user_data)65 static void game_controller_dummy_save(void *user_data)
66 {
67 }
68 
init_pif(struct pif * pif,void * eeprom_user_data,void (* eeprom_save)(void *),uint8_t * eeprom_data,size_t eeprom_size,uint16_t eeprom_id,void * af_rtc_user_data,const struct tm * (* af_rtc_get_time)(void *),const uint8_t * ipl3)69 void init_pif(struct pif *pif,
70       void *eeprom_user_data,
71       void (*eeprom_save)(void*),
72       uint8_t *eeprom_data,
73       size_t eeprom_size,
74       uint16_t eeprom_id,
75       void* af_rtc_user_data,
76       const struct tm* (*af_rtc_get_time)(void*),
77       const uint8_t *ipl3
78       )
79 {
80    size_t i;
81 
82    for (i = 0; i < GAME_CONTROLLERS_COUNT; ++i)
83    {
84       static  channels[] = { 0, 1, 2, 3 };
85       init_game_controller(
86             &pif->controllers[i],
87             (void*)&channels[i],
88             egcvip_is_connected,
89             egcvip_get_input,
90             NULL,
91             &game_controller_dummy_save,
92             &saved_memory.mempack[i][0],
93             &channels[i],
94             rvip_rumble
95             );
96    }
97 
98    init_eeprom(&pif->eeprom,
99          eeprom_user_data, eeprom_save, eeprom_data, eeprom_size, eeprom_id);
100    init_af_rtc(&pif->af_rtc, af_rtc_user_data, af_rtc_get_time);
101    init_cic_using_ipl3(&pif->cic, ipl3);
102 }
103 
poweron_pif(struct pif * pif)104 void poweron_pif(struct pif* pif)
105 {
106    memset(pif->ram, 0, PIF_RAM_SIZE);
107 }
108 
read_pif_ram(void * opaque,uint32_t address,uint32_t * value)109 int read_pif_ram(void* opaque, uint32_t address, uint32_t* value)
110 {
111    struct si_controller* si = (struct si_controller*)opaque;
112    uint32_t addr            = PIF_RAM_ADDR(address);
113 
114    if (addr >= PIF_RAM_SIZE)
115    {
116       DebugMessage(M64MSG_ERROR, "Invalid PIF address: %08x", address);
117       *value = 0;
118       return -1;
119    }
120 
121    memcpy(value, si->pif.ram + addr, sizeof(*value));
122    *value = sl(*value);
123    return 0;
124 }
125 
write_pif_ram(void * opaque,uint32_t address,uint32_t value,uint32_t mask)126 int write_pif_ram(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
127 {
128    struct si_controller* si = (struct si_controller*)opaque;
129    uint32_t addr            = PIF_RAM_ADDR(address);
130 
131    if (addr >= PIF_RAM_SIZE)
132    {
133       DebugMessage(M64MSG_ERROR, "Invalid PIF address: %08x", address);
134       return -1;
135    }
136 
137    si->pif.ram[addr] = MASKED_WRITE((uint32_t*)(&si->pif.ram[addr]), sl(value), sl(mask));
138 
139    if ((addr == 0x3c) && (mask & 0xff))
140    {
141       if (si->pif.ram[0x3f] == 0x08)
142       {
143          si->pif.ram[0x3f] = 0;
144          cp0_update_count();
145          add_interrupt_event(SI_INT, /*0x100*/0x900);
146       }
147       else
148       {
149          update_pif_write(si);
150       }
151    }
152    return 0;
153 }
154 
update_pif_write(struct si_controller * si)155 void update_pif_write(struct si_controller *si)
156 {
157    int i=0, channel=0;
158    struct pif* pif = &si->pif;
159 
160    pif->cic_challenge = 0;
161 
162    if (pif->ram[0x3F] > 1)
163    {
164       int8_t challenge[30], response[30];
165 
166       switch (pif->ram[0x3F])
167       {
168          case 0x02:
169 #ifdef DEBUG_PIF
170             DebugMessage(M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 2 - CIC challenge");
171 #endif
172             // format the 'challenge' message into 30 nibbles for X-Scale's CIC code
173             for (i = 0; i < 15; i++)
174             {
175                challenge[i*2] =   (pif->ram[48+i] >> 4) & 0x0f;
176                challenge[i*2+1] =  pif->ram[48+i]       & 0x0f;
177             }
178             // calculate the proper response for the given challenge (X-Scale's algorithm)
179             n64_cic_nus_6105(challenge, response, CHL_LEN - 2);
180             pif->ram[46] = 0;
181             pif->ram[47] = 0;
182             // re-format the 'response' into a byte stream
183             for (i = 0; i < 15; i++)
184                pif->ram[48+i] = (response[i*2] << 4) + response[i*2+1];
185             // the last byte (2 nibbles) is always 0
186             pif->ram[63] = 0;
187             pif->cic_challenge = 1;
188             break;
189          case 0x08:
190 #ifdef DEBUG_PIF
191             DebugMessage(M64MSG_INFO, "update_pif_write() pif_ram[0x3f] = 8");
192 #endif
193             pif->ram[0x3F] = 0;
194             break;
195          default:
196             DebugMessage(M64MSG_ERROR, "error in update_pif_write(): %x", pif->ram[0x3F]);
197       }
198       return;
199    }
200    while (i<0x40)
201    {
202       switch (pif->ram[i])
203       {
204          case 0x00:
205             channel++;
206             if (channel > 6) i=0x40;
207             break;
208          case 0xFF:
209             break;
210          default:
211             if (!(pif->ram[i] & 0xC0))
212             {
213                if (channel < 4)
214                {
215                   if (Controls[channel].Present && Controls[channel].RawData)
216                      input.controllerCommand(channel, &pif->ram[i]);
217                   else
218                      process_controller_command(&pif->controllers[channel], &pif->ram[i]);
219                }
220                else if (channel == 4)
221                   process_cart_command(pif, &pif->ram[i]);
222                else
223                   DebugMessage(M64MSG_ERROR, "channel >= 4 in update_pif_write");
224                i += pif->ram[i] + (pif->ram[(i+1)] & 0x3F) + 1;
225                channel++;
226             }
227             else
228                i=0x40;
229       }
230       i++;
231    }
232 
233    //pif->ram[0x3F] = 0;
234 
235    /* notify the INPUT plugin that we're at the end of PIF ram processing */
236    input.controllerCommand(-1, NULL);
237 }
238 
update_pif_read(struct si_controller * si)239 void update_pif_read(struct si_controller *si)
240 {
241    struct pif* pif = &si->pif;
242 
243    int i=0, channel=0;
244 
245    /* When PIF ram contains a CIC challenge result, do not
246     * process the memory as if it were normal commands. */
247    if (pif->cic_challenge)
248       return;
249 
250    while (i<0x40)
251    {
252       switch (pif->ram[i])
253       {
254          case 0x00:
255             channel++;
256             if (channel > 6) i=0x40;
257             break;
258          case 0xFE:
259             i = 0x40;
260             break;
261          case 0xFF:
262             break;
263          case 0xB4:
264          case 0x56:
265          case 0xB8:
266             break;
267          default:
268             if (!(pif->ram[i] & 0xC0))
269             {
270                if (channel < 4)
271                {
272                   if (Controls[channel].Present &&
273                         Controls[channel].RawData)
274                      input.readController(channel, &pif->ram[i]);
275                   else
276                      read_controller(&pif->controllers[channel], &pif->ram[i]);
277                }
278                i += pif->ram[i] + (pif->ram[(i+1)] & 0x3F) + 1;
279                channel++;
280             }
281             else
282                i=0x40;
283       }
284       i++;
285    }
286 
287    /* notify the INPUT plugin that we're at the end of PIF ram processing */
288    input.readController(-1, NULL);
289 }
290