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