/[pcsx2_0.9.7]/trunk/pcsx2/Sio.cpp
ViewVC logotype

Contents of /trunk/pcsx2/Sio.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (10 years, 4 months ago) by william
File size: 21408 byte(s)
committing r3113 initial commit again...
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "IopCommon.h"
18
19 #include "Sio.h"
20 #include "sio_internal.h"
21
22 _sio sio;
23
24 static const u8 cardh[4] = { 0xFF, 0xFF, 0x5a, 0x5d };
25
26 // Memory Card Specs for standard Sony 8mb carts:
27 // Flags (magic sio '+' thingie!), Sector size, eraseBlockSize (in pages), card size (in pages), xor checksum (superblock?), terminator (unused?).
28 static const mc_command_0x26_tag mc_sizeinfo_8mb= {'+', 512, 16, 0x4000, 0x52, 0x5A};
29
30 // Ejection timeout management belongs in the MemoryCardFile plugin, except the plugin
31 // interface is not yet complete.
32 static int m_ForceEjectionTimeout[2];
33
34 // SIO Inline'd IRQs : Calls the SIO interrupt handlers directly instead of
35 // feeding them through the IOP's branch test. (see SIO.H for details)
36
37 #ifdef SIO_INLINE_IRQS
38 #define SIO_INT() sioInterrupt()
39 #define SIO_FORCEINLINE __forceinline
40 #else
41 __forceinline void SIO_INT()
42 {
43 if( !(psxRegs.interrupt & (1<<IopEvt_SIO)) )
44 PSX_INT(IopEvt_SIO, 64 ); // PSXCLK/250000);
45 }
46 #define SIO_FORCEINLINE __forceinline
47 #endif
48
49 // Currently only check if pad wants mtap to be active.
50 // Could lets PCSX2 have its own options, if anyone ever
51 // wants to add support for using the extra memcard slots.
52 static bool IsMtapPresent( uint port )
53 {
54 return EmuConfig.MultitapEnabled( port );
55 //return (0 != PADqueryMtap(port+1));
56 }
57
58 static void _ReadMcd(u8 *data, u32 adr, int size)
59 {
60 SysPlugins.McdRead(
61 sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
62 data, adr, size
63 );
64 }
65
66 static void _SaveMcd(const u8 *data, u32 adr, int size)
67 {
68 SysPlugins.McdSave(
69 sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()],
70 data, adr, size
71 );
72 }
73
74 static void _EraseMCDBlock(u32 adr)
75 {
76 SysPlugins.McdEraseBlock( sio.GetMemcardIndex(), sio.activeMemcardSlot[sio.GetMemcardIndex()], adr );
77 }
78
79 static u8 sio_xor( const u8 *buf, uint length )
80 {
81 u8 i, x;
82 for (x=0, i=0; i<length; i++) x ^= buf[i];
83 return x;
84 }
85
86 template< typename T >
87 static void apply_xor( u8& dest, const T& src )
88 {
89 u8* buf = (u8*)&src;
90 for (uint x=0; x<sizeof(src); x++) dest ^= buf[x];
91 }
92
93 void sioInit()
94 {
95 memzero(sio);
96 memzero(m_ForceEjectionTimeout);
97
98 // Transfer(?) Ready and the Buffer is Empty
99 sio.StatReg = TX_RDY | TX_EMPTY;
100 sio.packetsize = 0;
101 sio.terminator = 0x55; // Command terminator 'U'
102 }
103
104 u8 sioRead8() {
105 u8 ret = 0xFF;
106
107 if (sio.StatReg & RX_RDY) {
108 ret = sio.buf[sio.parp];
109 if (sio.parp == sio.bufcount) {
110 sio.StatReg &= ~RX_RDY; // Receive is not Ready now?
111 sio.StatReg |= TX_EMPTY; // Buffer is Empty
112
113 if (sio.padst == 2) sio.padst = 0;
114 /*if (sio.mcdst == 1) {
115 sio.mcdst = 99;
116 sio.StatReg&= ~TX_EMPTY;
117 sio.StatReg|= RX_RDY;
118 }*/
119 }
120 }
121 //PAD_LOG("sio read8 ;ret = %x", ret);
122 return ret;
123 }
124
125 void SIO_CommandWrite(u8 value,int way) {
126 PAD_LOG("sio write8 %x", value);
127
128 // PAD COMMANDS
129 switch (sio.padst) {
130 case 1: SIO_INT();
131 if ((value&0x40) == 0x40) {
132 sio.padst = 2; sio.parp = 1;
133 switch (sio.CtrlReg&0x2002) {
134 case 0x0002:
135 sio.packetsize ++; // Total packet size sent
136 sio.buf[sio.parp] = PADpoll(value);
137 break;
138 case 0x2002:
139 sio.packetsize ++; // Total packet size sent
140 sio.buf[sio.parp] = PADpoll(value);
141 break;
142 }
143 if (!(sio.buf[sio.parp] & 0x0f)) {
144 sio.bufcount = 2 + 32;
145 } else {
146 sio.bufcount = 2 + (sio.buf[sio.parp] & 0x0f) * 2;
147 }
148 }
149 else sio.padst = 0;
150 return;
151 case 2:
152 sio.parp++;
153 switch (sio.CtrlReg&0x2002) {
154 case 0x0002: sio.packetsize ++; sio.buf[sio.parp] = PADpoll(value); break;
155 case 0x2002: sio.packetsize ++; sio.buf[sio.parp] = PADpoll(value); break;
156 }
157 if (sio.parp == sio.bufcount) { sio.padst = 0; return; }
158 SIO_INT();
159 return;
160 case 3:
161 // No pad connected.
162 sio.parp++;
163 if (sio.parp == sio.bufcount) { sio.padst = 0; return; }
164 SIO_INT();
165 return;
166 }
167
168 // MEMORY CARD COMMANDS
169 switch (sio.mcdst) {
170 case 1:
171 sio.packetsize++;
172 SIO_INT();
173 if (sio.rdwr) { sio.parp++; return; }
174 sio.parp = 1;
175 switch (value) {
176 case 0x11: // RESET
177 PAD_LOG("RESET MEMORY CARD");
178
179 sio.bufcount = 8;
180 memset8<0xff>(sio.buf);
181 sio.buf[3] = sio.terminator;
182 sio.buf[2] = '+';
183 sio.mcdst = 99;
184 sio2.packet.recvVal3 = 0x8c;
185 break;
186 case 0x12: // RESET
187 sio.bufcount = 8;
188 memset8<0xff>(sio.buf);
189 sio.buf[3] = sio.terminator;
190 sio.buf[2] = '+';
191 sio.mcdst = 99;
192
193 sio2.packet.recvVal3 = 0x8c;
194 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
195 break;
196 case 0x81: // COMMIT
197 sio.bufcount = 8;
198 memset8<0xff>(sio.buf);
199 sio.mcdst = 99;
200 sio.buf[3] = sio.terminator;
201 sio.buf[2] = '+';
202 sio2.packet.recvVal3 = 0x8c;
203 if(value == 0x81) {
204 if(sio.mc_command==0x42)
205 sio2.packet.recvVal1 = 0x1600; // Writing
206 else if(sio.mc_command==0x43) sio2.packet.recvVal1 = 0x1700; // Reading
207 }
208 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
209 break;
210 case 0x21:
211 case 0x22:
212 case 0x23: // SECTOR SET
213 sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0;
214 memset8<0xff>(sio.buf);
215 sio2.packet.recvVal3 = 0x8c;
216 sio.buf[8]=sio.terminator;
217 sio.buf[7]='+';
218 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
219 break;
220 case 0x24:
221 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
222 break;
223 case 0x25:
224 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
225 break;
226
227 case 0x26:
228 {
229 const uint port = sio.GetMemcardIndex();
230 const uint slot = sio.activeMemcardSlot[port];
231
232 mc_command_0x26_tag cmd = mc_sizeinfo_8mb;
233 PS2E_McdSizeInfo info;
234
235 info.SectorSize = cmd.sectorSize;
236 info.EraseBlockSizeInSectors = cmd.eraseBlocks;
237 info.McdSizeInSectors = cmd.mcdSizeInSectors;
238
239 SysPlugins.McdGetSizeInfo( port, slot, info );
240 pxAssumeDev( cmd.mcdSizeInSectors >= mc_sizeinfo_8mb.mcdSizeInSectors,
241 "Mcd plugin returned an invalid memorycard size: Cards smaller than 8MB are not supported." );
242
243 cmd.sectorSize = info.SectorSize;
244 cmd.eraseBlocks = info.EraseBlockSizeInSectors;
245 cmd.mcdSizeInSectors = info.McdSizeInSectors;
246
247 // Recalculate the xor summation
248 // This uses a trick of removing the known xor values for a default 8mb memorycard (for which the XOR
249 // was calculated), and replacing it with our new values.
250
251 apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.sectorSize );
252 apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.eraseBlocks );
253 apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.mcdSizeInSectors );
254
255 apply_xor( cmd.mc_xor, cmd.sectorSize );
256 apply_xor( cmd.mc_xor, cmd.eraseBlocks );
257 apply_xor( cmd.mc_xor, cmd.mcdSizeInSectors );
258
259 sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83;
260 memset8<0xff>(sio.buf);
261 memcpy_fast(&sio.buf[2], &cmd, sizeof(cmd));
262 sio.buf[12]=sio.terminator;
263 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
264 }
265 break;
266
267 case 0x27:
268 case 0x28:
269 case 0xBF:
270 sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b;
271 memset8<0xff>(sio.buf);
272 sio.buf[4]=sio.terminator;
273 sio.buf[3]='+';
274 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
275 break;
276 case 0x42: // WRITE
277 case 0x43: // READ
278 case 0x82:
279 if(value==0x82 && sio.lastsector==sio.sector) sio.mode = 2;
280 if(value==0x42) sio.mode = 0;
281 if(value==0x43) sio.lastsector = sio.sector; // Reading
282
283 sio.bufcount =133; sio.mcdst = 99;
284 memset8<0xff>(sio.buf);
285 sio.buf[133]=sio.terminator;
286 sio.buf[132]='+';
287 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
288 break;
289 case 0xf0:
290 case 0xf1:
291 case 0xf2:
292 sio.mcdst = 99;
293 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
294 break;
295 case 0xf3:
296 case 0xf7:
297 sio.bufcount = 4; sio.mcdst = 99;
298 memset8<0xff>(sio.buf);
299 sio.buf[4]=sio.terminator;
300 sio.buf[3]='+';
301 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
302 break;
303 case 0x52:
304 sio.rdwr = 1; memset8<0xff>(sio.buf);
305 sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
306 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
307 break;
308 case 0x57:
309 sio.rdwr = 2; memset8<0xff>(sio.buf);
310 sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
311 MEMCARDS_LOG("MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
312 break;
313 default:
314 sio.mcdst = 0;
315 memset8<0xff>(sio.buf);
316 sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
317 MEMCARDS_LOG("Unknown MC(%d) command 0x%02X", sio.GetMemcardIndex()+1, value);
318 }
319 sio.mc_command=value;
320 return;
321 // FURTHER PROCESSING OF THE MEMORY CARD COMMANDS
322 case 99:
323 sio.packetsize++;
324 sio.parp++;
325 switch(sio.mc_command)
326 {
327 // SET_ERASE_PAGE; the next erase commands will *clear* data starting with the page set here
328 case 0x21:
329 // SET_WRITE_PAGE; the next write commands will commit data starting with the page set here
330 case 0x22:
331 // SET_READ_PAGE; the next read commands will return data starting with the page set here
332 case 0x23:
333 if (sio.parp==2)sio.sector|=(value & 0xFF)<< 0;
334 if (sio.parp==3)sio.sector|=(value & 0xFF)<< 8;
335 if (sio.parp==4)sio.sector|=(value & 0xFF)<<16;
336 if (sio.parp==5)sio.sector|=(value & 0xFF)<<24;
337 if (sio.parp==6)
338 {
339 if (sio_xor((u8 *)&sio.sector, 4) == value)
340 MEMCARDS_LOG("MC(%d) SET PAGE sio.sector, sector=0x%04X", sio.GetMemcardIndex()+1, sio.sector);
341 else
342 MEMCARDS_LOG("MC(%d) SET PAGE XOR value ERROR 0x%02X != ^0x%02X",
343 sio.GetMemcardIndex()+1, value, sio_xor((u8 *)&sio.sector, 4));
344 }
345 break;
346
347 // SET_TERMINATOR; reads the new terminator code
348 case 0x27:
349 if(sio.parp==2) {
350 sio.terminator = value;
351 sio.buf[4] = value;
352 MEMCARDS_LOG("MC(%d) SET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value);
353
354 }
355 break;
356
357 // GET_TERMINATOR; puts in position 3 the current terminator code and in 4 the default one
358 // depending on the param
359 case 0x28:
360 if(sio.parp == 2) {
361 sio.buf[2] = '+';
362 sio.buf[3] = sio.terminator;
363
364 //if(value == 0) sio.buf[4] = 0xFF;
365 sio.buf[4] = 0x55;
366 MEMCARDS_LOG("MC(%d) GET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value);
367 }
368 break;
369 // WRITE DATA
370 case 0x42:
371 if (sio.parp==2) {
372 sio.bufcount=5+value;
373 memset8<0xff>(sio.buf);
374 sio.buf[sio.bufcount-1]='+';
375 sio.buf[sio.bufcount]=sio.terminator;
376 MEMCARDS_LOG("MC(%d) WRITE command, size=0x%02X", sio.GetMemcardIndex()+1, value);
377 }
378 else
379 if ((sio.parp>2) && (sio.parp<sio.bufcount-2)) {
380 sio.buf[sio.parp]=value;
381 //MEMCARDS_LOG("MC(%d) WRITING 0x%02X", sio.GetMemcardIndex()+1, value);
382 } else
383 if (sio.parp==sio.bufcount-2) {
384 if (sio_xor(&sio.buf[3], sio.bufcount-5)==value) {
385 _SaveMcd(&sio.buf[3], (512+16)*sio.sector+sio.k, sio.bufcount-5);
386 sio.buf[sio.bufcount-1]=value;
387 sio.k+=sio.bufcount-5;
388 } else {
389 MEMCARDS_LOG("MC(%d) write XOR value error 0x%02X != ^0x%02X",
390 sio.GetMemcardIndex()+1, value, sio_xor(&sio.buf[3], sio.bufcount-5));
391 }
392 }
393 break;
394 // READ DATA
395 case 0x43:
396 if (sio.parp==2)
397 {
398 //int i;
399 sio.bufcount=value+5;
400 sio.buf[3]='+';
401 MEMCARDS_LOG("MC(%d) READ command, size=0x%02X", sio.GetMemcardIndex()+1, value);
402 _ReadMcd(&sio.buf[4], (512+16)*sio.sector+sio.k, value);
403
404 /*if(sio.mode==2)
405 {
406 int j;
407 for(j=0; j < value; j++)
408 sio.buf[4+j] = ~sio.buf[4+j];
409 }*/
410
411 sio.k+=value;
412 sio.buf[sio.bufcount-1]=sio_xor(&sio.buf[4], value);
413 sio.buf[sio.bufcount]=sio.terminator;
414 }
415 break;
416 // INTERNAL ERASE
417 case 0x82:
418 if(sio.parp==2)
419 {
420 sio.buf[2]='+';
421 sio.buf[3]=sio.terminator;
422 //if (sio.k != 0 || (sio.sector & 0xf) != 0)
423 // Console.Warning("saving : odd position for erase.");
424
425 _EraseMCDBlock((512+16)*(sio.sector&~0xf));
426
427 /* memset(sio.buf, -1, 256);
428 _SaveMcd(sio.buf, (512+16)*sio.sector, 256);
429 _SaveMcd(sio.buf, (512+16)*sio.sector+256, 256);
430 _SaveMcd(sio.buf, (512+16)*sio.sector+512, 16);
431 sio.buf[2]='+';
432 sio.buf[3]=sio.terminator;*/
433 //sio.buf[sio.bufcount] = sio.terminator;
434 MEMCARDS_LOG("MC(%d) INTERNAL ERASE command 0x%02X", sio.GetMemcardIndex()+1, value);
435 }
436 break;
437 // CARD AUTHENTICATION CHECKS
438 case 0xF0:
439 if (sio.parp==2)
440 {
441 MEMCARDS_LOG("MC(%d) CARD AUTH :0x%02X", sio.GetMemcardIndex()+1, value);
442 switch(value){
443 case 1:
444 case 2:
445 case 4:
446 case 15:
447 case 17:
448 case 19:
449 sio.bufcount=13;
450 memset8<0xff>(sio.buf);
451 sio.buf[12] = 0; // Xor value of data from index 4 to 11
452 sio.buf[3]='+';
453 sio.buf[13] = sio.terminator;
454 break;
455 case 6:
456 case 7:
457 case 11:
458 sio.bufcount=13;
459 memset8<0xff>(sio.buf);
460 sio.buf[12]='+';
461 sio.buf[13] = sio.terminator;
462 break;
463 default:
464 sio.bufcount=4;
465 memset8<0xff>(sio.buf);
466 sio.buf[3]='+';
467 sio.buf[4] = sio.terminator;
468 }
469 }
470 break;
471 }
472 if (sio.bufcount<=sio.parp) sio.mcdst = 0;
473 return;
474 }
475
476 switch (sio.mtapst)
477 {
478 case 0x1:
479 sio.packetsize++;
480 sio.parp = 1;
481 SIO_INT();
482 switch(value) {
483 case 0x12:
484 // Query number of pads supported.
485 sio.buf[3] = 4;
486 sio.mtapst = 2;
487 sio.bufcount = 5;
488 break;
489 case 0x13:
490 // Query number of memcards supported.
491 sio.buf[3] = 4;
492 sio.mtapst = 2;
493 sio.bufcount = 5;
494 break;
495 case 0x21:
496 // Set pad slot.
497 sio.mtapst = value;
498 sio.bufcount = 6; // No idea why this is 6, saved from old code.
499 break;
500 case 0x22:
501 // Set memcard slot.
502 sio.mtapst = value;
503 sio.bufcount = 6; // No idea why this is 6, saved from old code.
504 break;
505 }
506 // Commented out values are from original code. They break multitap in bios.
507 sio.buf[sio.bufcount-1]=0;//'+';
508 sio.buf[sio.bufcount]=0;//'Z';
509 return;
510 case 0x2:
511 sio.packetsize++;
512 sio.parp++;
513 if (sio.bufcount<=sio.parp) sio.mcdst = 0;
514 SIO_INT();
515 return;
516 case 0x21:
517 // Set pad slot.
518 sio.packetsize++;
519 sio.parp++;
520 sio.mtapst = 2;
521 if (sio.CtrlReg & 2)
522 {
523 int port = sio.GetMultitapPort();
524 if (IsMtapPresent(port))
525 sio.activePadSlot[port] = value;
526 }
527 SIO_INT();
528 return;
529 case 0x22:
530 // Set memcard slot.
531 sio.packetsize++;
532 sio.parp++;
533 sio.mtapst = 2;
534 if (sio.CtrlReg & 2)
535 {
536 int port = sio.GetMultitapPort();
537 if (IsMtapPresent(port))
538 sio.activeMemcardSlot[port] = value;
539 }
540 SIO_INT();
541 return;
542 }
543
544 if(sio.count == 1 || way == 0) InitializeSIO(value);
545 }
546
547 void InitializeSIO(u8 value)
548 {
549 switch (value) {
550 case 0x01: // start pad
551 sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
552 sio.StatReg |= RX_RDY; // Transfer is Ready
553
554 sio.bufcount = 4; // Default size, when no pad connected.
555 sio.parp = 0;
556 sio.padst = 1;
557 sio.packetsize = 1;
558 sio.count = 0;
559 sio2.packet.recvVal1 = 0x1100; // Pad is present
560
561 if( (sio.CtrlReg & 2) == 2 )
562 {
563 int padslot = (sio.CtrlReg>>12) & 2; // move 0x2000 bitmask into leftmost bits
564 if( padslot != 1 )
565 {
566 padslot >>= 1; // transform 0/2 to be 0/1 values
567
568 if (!PADsetSlot(padslot+1, 1+sio.activePadSlot[padslot]) && sio.activePadSlot[padslot])
569 {
570 // Pad is not present. Don't send poll, just return a bunch of 0's.
571 sio2.packet.recvVal1 = 0x1D100;
572 sio.padst = 3;
573 }
574 else {
575 sio.buf[0] = PADstartPoll(padslot+1);
576 }
577 }
578 }
579
580 SIO_INT();
581 return;
582
583 case 0x21: // start mtap
584 sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
585 sio.StatReg |= RX_RDY; // Transfer is Ready
586 sio.parp = 0;
587 sio.packetsize = 1;
588 sio.mtapst = 1;
589 sio.count = 0;
590 sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :(
591 if (sio.CtrlReg & 2) // No idea if this test is needed. Pads use it, memcards don't.
592 {
593 int port = sio.GetMultitapPort();
594 if (!IsMtapPresent(port))
595 {
596 // If "unplug" multitap mid game, set active slots to 0.
597 sio.activePadSlot[port] = 0;
598 sio.activeMemcardSlot[port] = 0;
599 }
600 else
601 {
602 sio.bufcount = 3;
603 sio.buf[0] = 0xFF;
604 sio.buf[1] = 0x80; // Have no idea if this is correct. From PSX mtap.
605 sio.buf[2] = 0x5A;
606 sio2.packet.recvVal1 = 0x1100; // Mtap is connected :)
607 }
608 }
609 SIO_INT();
610 return;
611
612 case 0x61: // start remote control sensor
613 sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
614 sio.StatReg |= RX_RDY; // Transfer is Ready
615 sio.parp = 0;
616 sio.packetsize = 1;
617 sio.count = 0;
618 sio2.packet.recvVal1 = 0x1100; // Pad is present
619 SIO_INT();
620 return;
621
622 case 0x81: // start memcard
623 {
624 sio.StatReg &= ~TX_EMPTY;
625 sio.StatReg |= RX_RDY;
626 memcpy(sio.buf, cardh, 4);
627 sio.parp = 0;
628 sio.bufcount = 8;
629 sio.mcdst = 1;
630 sio.packetsize = 1;
631 sio.rdwr = 0;
632 sio.count = 0;
633
634 // Memcard presence reporting!
635 // Note:
636 // 0x01100 means Memcard is present
637 // 0x1D100 means Memcard is missing.
638
639 const uint port = sio.GetMemcardIndex();
640 const uint slot = sio.activeMemcardSlot[port];
641
642 // forced ejection logic. Technically belongs in the McdIsPresent handler for
643 // the plugin, once the memorycard plugin system is completed.
644 // (ejection is only supported for the default non-multitap cards at this time)
645
646 bool forceEject = false;
647 if( slot == 0 && m_ForceEjectionTimeout[port] )
648 {
649 --m_ForceEjectionTimeout[port];
650 forceEject = true;
651 }
652
653 if( !forceEject && SysPlugins.McdIsPresent( port, slot ) )
654 {
655 sio2.packet.recvVal1 = 0x1100;
656 PAD_LOG("START MEMCARD [port:%d, slot:%d] - Present", port, slot );
657 }
658 else
659 {
660 sio2.packet.recvVal1 = 0x1D100;
661 PAD_LOG("START MEMCARD [port:%d, slot:%d] - Missing", port, slot );
662 }
663
664 SIO_INT();
665 }
666 return;
667 }
668 }
669
670 void sioWrite8(u8 value)
671 {
672 SIO_CommandWrite(value,0);
673 }
674
675 void SIODMAWrite(u8 value)
676 {
677 SIO_CommandWrite(value,1);
678 }
679
680 void sioWriteCtrl16(u16 value) {
681 sio.CtrlReg = value & ~RESET_ERR;
682 if (value & RESET_ERR) sio.StatReg &= ~IRQ;
683 if ((sio.CtrlReg & SIO_RESET) || (!sio.CtrlReg))
684 {
685 sio.mtapst = 0; sio.padst = 0; sio.mcdst = 0; sio.parp = 0;
686 sio.StatReg = TX_RDY | TX_EMPTY;
687 psxRegs.interrupt &= ~(1<<IopEvt_SIO);
688 }
689 }
690
691 void SIO_FORCEINLINE sioInterrupt() {
692 PAD_LOG("Sio Interrupt");
693 sio.StatReg|= IRQ;
694 psxHu32(0x1070)|=0x80;
695 }
696
697 void SaveStateBase::sioFreeze()
698 {
699 // CRCs for memory cards.
700 u64 m_mcdCRCs[2][8];
701
702 FreezeTag( "sio" );
703 Freeze( sio );
704
705 // TODO : This stuff should all be moved to the memorycard plugin eventually,
706 // but that requires adding memorycard plugin to the savestate, and I'm not in
707 // the mood to do that (let's plan it for 0.9.8) --air
708
709 // Note: The Ejection system only works for the default non-multitap MemoryCards
710 // only. This is because it could become very (very!) slow to do a full CRC check
711 // on multiple 32 or 64 meg carts. I have chosen to save
712
713 if( IsSaving() )
714 {
715 for( uint port=0; port<2; ++port )
716 //for( uint slot=0; slot<4; ++slot )
717 {
718 const uint slot = 0; // see above comment about multitap slowness
719 m_mcdCRCs[port][slot] = SysPlugins.McdGetCRC( port, slot );
720 }
721 }
722
723 Freeze( m_mcdCRCs );
724
725 if( IsLoading() && EmuConfig.McdEnableEjection )
726 {
727 // Notes on the ForceEjectionTimeout:
728 // * TOTA works with values as low as 20 here.
729 // It "times out" with values around 1800 (forces user to check the memcard
730 // twice to find it). Other games could be different. :|
731 //
732 // * At 64: Disgaea 1 and 2, and Grandia 2 end up displaying a quick "no memcard!"
733 // notice before finding the memorycard and re-enumerating it. A very minor
734 // annoyance, but no breakages.
735
736 // * GuitarHero will break completely with almost any value here, by design, because
737 // it has a "rule" that the memcard should never be ejected during a song. So by
738 // ejecting it, the game freezes (which is actually good emulation, but annoying!)
739
740 for( uint port=0; port<2; ++port )
741 //for( int slot=0; slot<4; ++slot )
742 {
743 const uint slot = 0; // see above comment about multitap slowness
744 u64 newCRC = SysPlugins.McdGetCRC( port, slot );
745 if( newCRC != m_mcdCRCs[port][slot] )
746 {
747 //m_mcdCRCs[port][slot] = newCRC;
748 m_ForceEjectionTimeout[port] = 128;
749 }
750 }
751 }
752 }
753

  ViewVC Help
Powered by ViewVC 1.1.22