/[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 62 - (show annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 4 months ago) by william
File size: 21272 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
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 __fi
40 #else
41 __fi void SIO_INT()
42 {
43 if( !(psxRegs.interrupt & (1<<IopEvt_SIO)) )
44 PSX_INT(IopEvt_SIO, 64 ); // PSXCLK/250000);
45 }
46 #define SIO_FORCEINLINE __fi
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 {
172 sio.packetsize++;
173 SIO_INT();
174 if (sio.rdwr) { sio.parp++; return; }
175 sio.parp = 1;
176
177 const char* log_cmdname = "";
178
179 switch (value) {
180 case 0x11: // RESET
181 log_cmdname = "Reset1";
182
183 sio.bufcount = 8;
184 memset8<0xff>(sio.buf);
185 sio.buf[3] = sio.terminator;
186 sio.buf[2] = '+';
187 sio.mcdst = 99;
188 sio2.packet.recvVal3 = 0x8c;
189 break;
190
191 // FIXME : Why are there two identical cases for resetting the
192 // memorycard(s)? there doesn't appear to be anything dealing with
193 // card slots here. --air
194 case 0x12: // RESET
195 log_cmdname = "Reset2";
196 sio.bufcount = 8;
197 memset8<0xff>(sio.buf);
198 sio.buf[3] = sio.terminator;
199 sio.buf[2] = '+';
200 sio.mcdst = 99;
201 sio2.packet.recvVal3 = 0x8c;
202 break;
203
204 case 0x81: // COMMIT
205 log_cmdname = "Commit";
206 sio.bufcount = 8;
207 memset8<0xff>(sio.buf);
208 sio.mcdst = 99;
209 sio.buf[3] = sio.terminator;
210 sio.buf[2] = '+';
211 sio2.packet.recvVal3 = 0x8c;
212 if(value == 0x81) {
213 if(sio.mc_command==0x42)
214 sio2.packet.recvVal1 = 0x1600; // Writing
215 else if(sio.mc_command==0x43) sio2.packet.recvVal1 = 0x1700; // Reading
216 }
217 break;
218 case 0x21:
219 case 0x22:
220 case 0x23: // SECTOR SET
221 log_cmdname = "SetSector";
222 sio.bufcount = 8; sio.mcdst = 99; sio.sector=0; sio.k=0;
223 memset8<0xff>(sio.buf);
224 sio2.packet.recvVal3 = 0x8c;
225 sio.buf[8]=sio.terminator;
226 sio.buf[7]='+';
227 break;
228
229 case 0x24: break;
230 case 0x25: break;
231
232 case 0x26:
233 {
234 log_cmdname = "GetInfo";
235
236 const uint port = sio.GetMemcardIndex();
237 const uint slot = sio.activeMemcardSlot[port];
238
239 mc_command_0x26_tag cmd = mc_sizeinfo_8mb;
240 PS2E_McdSizeInfo info;
241
242 info.SectorSize = cmd.sectorSize;
243 info.EraseBlockSizeInSectors = cmd.eraseBlocks;
244 info.McdSizeInSectors = cmd.mcdSizeInSectors;
245
246 SysPlugins.McdGetSizeInfo( port, slot, info );
247 pxAssumeDev( cmd.mcdSizeInSectors >= mc_sizeinfo_8mb.mcdSizeInSectors,
248 "Mcd plugin returned an invalid memorycard size: Cards smaller than 8MB are not supported." );
249
250 cmd.sectorSize = info.SectorSize;
251 cmd.eraseBlocks = info.EraseBlockSizeInSectors;
252 cmd.mcdSizeInSectors = info.McdSizeInSectors;
253
254 // Recalculate the xor summation
255 // This uses a trick of removing the known xor values for a default 8mb memorycard (for which the XOR
256 // was calculated), and replacing it with our new values.
257
258 apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.sectorSize );
259 apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.eraseBlocks );
260 apply_xor( cmd.mc_xor, mc_sizeinfo_8mb.mcdSizeInSectors );
261
262 apply_xor( cmd.mc_xor, cmd.sectorSize );
263 apply_xor( cmd.mc_xor, cmd.eraseBlocks );
264 apply_xor( cmd.mc_xor, cmd.mcdSizeInSectors );
265
266 sio.bufcount = 12; sio.mcdst = 99; sio2.packet.recvVal3 = 0x83;
267 memset8<0xff>(sio.buf);
268 memcpy_fast(&sio.buf[2], &cmd, sizeof(cmd));
269 sio.buf[12]=sio.terminator;
270 }
271 break;
272
273 case 0x27:
274 case 0x28:
275 case 0xBF:
276 log_cmdname = "NotSure"; // FIXME !!
277 sio.bufcount = 4; sio.mcdst = 99; sio2.packet.recvVal3 = 0x8b;
278 memset8<0xff>(sio.buf);
279 sio.buf[4]=sio.terminator;
280 sio.buf[3]='+';
281 break;
282
283 // FIXME ?
284 // sio.lastsector and sio.mode are unused.
285
286 case 0x42: // WRITE
287 log_cmdname = "Write";
288 //sio.mode = 0;
289 goto __doReadWrite;
290
291 case 0x43: // READ
292 log_cmdname = "Read";
293 //sio.lastsector = sio.sector; // Reading
294 goto __doReadWrite;
295
296 case 0x82:
297 log_cmdname = "Read(?)"; // FIXME !!
298 //if(sio.lastsector==sio.sector) sio.mode = 2;
299
300 __doReadWrite:
301 sio.bufcount =133; sio.mcdst = 99;
302 memset8<0xff>(sio.buf);
303 sio.buf[133]=sio.terminator;
304 sio.buf[132]='+';
305 break;
306
307
308 case 0xf0:
309 case 0xf1:
310 case 0xf2:
311 log_cmdname = "NoClue"; // FIXME !!
312 sio.mcdst = 99;
313 break;
314
315 case 0xf3:
316 case 0xf7:
317 log_cmdname = "NoClueHereEither"; // FIXME !!
318 sio.bufcount = 4; sio.mcdst = 99;
319 memset8<0xff>(sio.buf);
320 sio.buf[4]=sio.terminator;
321 sio.buf[3]='+';
322 break;
323
324 case 0x52:
325 log_cmdname = "FixMe"; // FIXME !!
326 sio.rdwr = 1; memset8<0xff>(sio.buf);
327 sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
328 break;
329 case 0x57:
330 log_cmdname = "FixMe"; // FIXME !!
331 sio.rdwr = 2; memset8<0xff>(sio.buf);
332 sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
333 break;
334 default:
335 log_cmdname = "Unknown";
336 sio.mcdst = 0;
337 memset8<0xff>(sio.buf);
338 sio.buf[sio.bufcount]=sio.terminator; sio.buf[sio.bufcount-1]='+';
339 }
340 MEMCARDS_LOG("MC(%d) command 0x%02X [%s]", sio.GetMemcardIndex()+1, value, log_cmdname);
341 sio.mc_command = value;
342 }
343 return; // END CASE 1.
344
345 // FURTHER PROCESSING OF THE MEMORY CARD COMMANDS
346 case 99:
347 {
348 sio.packetsize++;
349 sio.parp++;
350 switch(sio.mc_command)
351 {
352 // SET_ERASE_PAGE; the next erase commands will *clear* data starting with the page set here
353 case 0x21:
354 // SET_WRITE_PAGE; the next write commands will commit data starting with the page set here
355 case 0x22:
356 // SET_READ_PAGE; the next read commands will return data starting with the page set here
357 case 0x23:
358 if (sio.parp==2)sio.sector|=(value & 0xFF)<< 0;
359 if (sio.parp==3)sio.sector|=(value & 0xFF)<< 8;
360 if (sio.parp==4)sio.sector|=(value & 0xFF)<<16;
361 if (sio.parp==5)sio.sector|=(value & 0xFF)<<24;
362 if (sio.parp==6)
363 {
364 if (sio_xor((u8 *)&sio.sector, 4) == value)
365 MEMCARDS_LOG("MC(%d) SET PAGE sio.sector, sector=0x%04X", sio.GetMemcardIndex()+1, sio.sector);
366 else
367 MEMCARDS_LOG("MC(%d) SET PAGE XOR value ERROR 0x%02X != ^0x%02X",
368 sio.GetMemcardIndex()+1, value, sio_xor((u8 *)&sio.sector, 4));
369 }
370 break;
371
372 // SET_TERMINATOR; reads the new terminator code
373 case 0x27:
374 if(sio.parp==2) {
375 sio.terminator = value;
376 sio.buf[4] = value;
377 MEMCARDS_LOG("MC(%d) SET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value);
378
379 }
380 break;
381
382 // GET_TERMINATOR; puts in position 3 the current terminator code and in 4 the default one
383 // depending on the param
384 case 0x28:
385 if(sio.parp == 2) {
386 sio.buf[2] = '+';
387 sio.buf[3] = sio.terminator;
388
389 //if(value == 0) sio.buf[4] = 0xFF;
390 sio.buf[4] = 0x55;
391 MEMCARDS_LOG("MC(%d) GET TERMINATOR command, value=0x%02X", sio.GetMemcardIndex()+1, value);
392 }
393 break;
394 // WRITE DATA
395 case 0x42:
396 if (sio.parp==2) {
397 sio.bufcount=5+value;
398 memset8<0xff>(sio.buf);
399 sio.buf[sio.bufcount-1]='+';
400 sio.buf[sio.bufcount]=sio.terminator;
401 MEMCARDS_LOG("MC(%d) WRITE command, size=0x%02X", sio.GetMemcardIndex()+1, value);
402 }
403 else
404 if ((sio.parp>2) && (sio.parp<sio.bufcount-2)) {
405 sio.buf[sio.parp]=value;
406 //MEMCARDS_LOG("MC(%d) WRITING 0x%02X", sio.GetMemcardIndex()+1, value);
407 } else
408 if (sio.parp==sio.bufcount-2) {
409 if (sio_xor(&sio.buf[3], sio.bufcount-5)==value) {
410 _SaveMcd(&sio.buf[3], (512+16)*sio.sector+sio.k, sio.bufcount-5);
411 sio.buf[sio.bufcount-1]=value;
412 sio.k+=sio.bufcount-5;
413 } else {
414 MEMCARDS_LOG("MC(%d) write XOR value error 0x%02X != ^0x%02X",
415 sio.GetMemcardIndex()+1, value, sio_xor(&sio.buf[3], sio.bufcount-5));
416 }
417 }
418 break;
419 // READ DATA
420 case 0x43:
421 if (sio.parp==2)
422 {
423 //int i;
424 sio.bufcount=value+5;
425 sio.buf[3]='+';
426 MEMCARDS_LOG("MC(%d) READ command, size=0x%02X", sio.GetMemcardIndex()+1, value);
427 _ReadMcd(&sio.buf[4], (512+16)*sio.sector+sio.k, value);
428
429 /*if(sio.mode==2)
430 {
431 int j;
432 for(j=0; j < value; j++)
433 sio.buf[4+j] = ~sio.buf[4+j];
434 }*/
435
436 sio.k+=value;
437 sio.buf[sio.bufcount-1]=sio_xor(&sio.buf[4], value);
438 sio.buf[sio.bufcount]=sio.terminator;
439 }
440 break;
441 // INTERNAL ERASE
442 case 0x82:
443 if(sio.parp==2)
444 {
445 sio.buf[2]='+';
446 sio.buf[3]=sio.terminator;
447 //if (sio.k != 0 || (sio.sector & 0xf) != 0)
448 // Console.Warning("saving : odd position for erase.");
449
450 _EraseMCDBlock((512+16)*(sio.sector&~0xf));
451
452 /* memset(sio.buf, -1, 256);
453 _SaveMcd(sio.buf, (512+16)*sio.sector, 256);
454 _SaveMcd(sio.buf, (512+16)*sio.sector+256, 256);
455 _SaveMcd(sio.buf, (512+16)*sio.sector+512, 16);
456 sio.buf[2]='+';
457 sio.buf[3]=sio.terminator;*/
458 //sio.buf[sio.bufcount] = sio.terminator;
459 MEMCARDS_LOG("MC(%d) INTERNAL ERASE command 0x%02X", sio.GetMemcardIndex()+1, value);
460 }
461 break;
462 // CARD AUTHENTICATION CHECKS
463 case 0xF0:
464 if (sio.parp==2)
465 {
466 MEMCARDS_LOG("MC(%d) CARD AUTH :0x%02X", sio.GetMemcardIndex()+1, value);
467 switch(value){
468 case 1:
469 case 2:
470 case 4:
471 case 15:
472 case 17:
473 case 19:
474 sio.bufcount=13;
475 memset8<0xff>(sio.buf);
476 sio.buf[12] = 0; // Xor value of data from index 4 to 11
477 sio.buf[3]='+';
478 sio.buf[13] = sio.terminator;
479 break;
480 case 6:
481 case 7:
482 case 11:
483 sio.bufcount=13;
484 memset8<0xff>(sio.buf);
485 sio.buf[12]='+';
486 sio.buf[13] = sio.terminator;
487 break;
488 default:
489 sio.bufcount=4;
490 memset8<0xff>(sio.buf);
491 sio.buf[3]='+';
492 sio.buf[4] = sio.terminator;
493 }
494 }
495 break;
496 }
497 if (sio.bufcount<=sio.parp) sio.mcdst = 0;
498 }
499 return; // END CASE 99.
500 }
501
502 switch (sio.mtapst)
503 {
504 case 0x1:
505 sio.packetsize++;
506 sio.parp = 1;
507 SIO_INT();
508 switch(value) {
509 case 0x12:
510 // Query number of pads supported.
511 sio.buf[3] = 4;
512 sio.mtapst = 2;
513 sio.bufcount = 5;
514 break;
515 case 0x13:
516 // Query number of memcards supported.
517 sio.buf[3] = 4;
518 sio.mtapst = 2;
519 sio.bufcount = 5;
520 break;
521 case 0x21:
522 // Set pad slot.
523 sio.mtapst = value;
524 sio.bufcount = 6; // No idea why this is 6, saved from old code.
525 break;
526 case 0x22:
527 // Set memcard slot.
528 sio.mtapst = value;
529 sio.bufcount = 6; // No idea why this is 6, saved from old code.
530 break;
531 }
532 // Commented out values are from original code. They break multitap in bios.
533 sio.buf[sio.bufcount-1]=0;//'+';
534 sio.buf[sio.bufcount]=0;//'Z';
535 return;
536 case 0x2:
537 sio.packetsize++;
538 sio.parp++;
539 if (sio.bufcount<=sio.parp) sio.mcdst = 0;
540 SIO_INT();
541 return;
542 case 0x21:
543 // Set pad slot.
544 sio.packetsize++;
545 sio.parp++;
546 sio.mtapst = 2;
547 if (sio.CtrlReg & 2)
548 {
549 int port = sio.GetMultitapPort();
550 if (IsMtapPresent(port))
551 sio.activePadSlot[port] = value;
552 }
553 SIO_INT();
554 return;
555 case 0x22:
556 // Set memcard slot.
557 sio.packetsize++;
558 sio.parp++;
559 sio.mtapst = 2;
560 if (sio.CtrlReg & 2)
561 {
562 int port = sio.GetMultitapPort();
563 if (IsMtapPresent(port))
564 sio.activeMemcardSlot[port] = value;
565 }
566 SIO_INT();
567 return;
568 }
569
570 if(sio.count == 1 || way == 0) InitializeSIO(value);
571 }
572
573 void InitializeSIO(u8 value)
574 {
575 switch (value) {
576 case 0x01: // start pad
577 sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
578 sio.StatReg |= RX_RDY; // Transfer is Ready
579
580 sio.bufcount = 4; // Default size, when no pad connected.
581 sio.parp = 0;
582 sio.padst = 1;
583 sio.packetsize = 1;
584 sio.count = 0;
585 sio2.packet.recvVal1 = 0x1100; // Pad is present
586
587 if( (sio.CtrlReg & 2) == 2 )
588 {
589 int padslot = (sio.CtrlReg>>12) & 2; // move 0x2000 bitmask into leftmost bits
590 if( padslot != 1 )
591 {
592 padslot >>= 1; // transform 0/2 to be 0/1 values
593
594 if (!PADsetSlot(padslot+1, 1+sio.activePadSlot[padslot]) && sio.activePadSlot[padslot])
595 {
596 // Pad is not present. Don't send poll, just return a bunch of 0's.
597 sio2.packet.recvVal1 = 0x1D100;
598 sio.padst = 3;
599 }
600 else {
601 sio.buf[0] = PADstartPoll(padslot+1);
602 }
603 }
604 }
605
606 SIO_INT();
607 return;
608
609 case 0x21: // start mtap
610 sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
611 sio.StatReg |= RX_RDY; // Transfer is Ready
612 sio.parp = 0;
613 sio.packetsize = 1;
614 sio.mtapst = 1;
615 sio.count = 0;
616 sio2.packet.recvVal1 = 0x1D100; // Mtap is not connected :(
617 if (sio.CtrlReg & 2) // No idea if this test is needed. Pads use it, memcards don't.
618 {
619 int port = sio.GetMultitapPort();
620 if (!IsMtapPresent(port))
621 {
622 // If "unplug" multitap mid game, set active slots to 0.
623 sio.activePadSlot[port] = 0;
624 sio.activeMemcardSlot[port] = 0;
625 }
626 else
627 {
628 sio.bufcount = 3;
629 sio.buf[0] = 0xFF;
630 sio.buf[1] = 0x80; // Have no idea if this is correct. From PSX mtap.
631 sio.buf[2] = 0x5A;
632 sio2.packet.recvVal1 = 0x1100; // Mtap is connected :)
633 }
634 }
635 SIO_INT();
636 return;
637
638 case 0x61: // start remote control sensor
639 sio.StatReg &= ~TX_EMPTY; // Now the Buffer is not empty
640 sio.StatReg |= RX_RDY; // Transfer is Ready
641 sio.parp = 0;
642 sio.packetsize = 1;
643 sio.count = 0;
644 sio2.packet.recvVal1 = 0x1100; // Pad is present
645 SIO_INT();
646 return;
647
648 case 0x81: // start memcard
649 {
650 sio.StatReg &= ~TX_EMPTY;
651 sio.StatReg |= RX_RDY;
652 memcpy(sio.buf, cardh, 4);
653 sio.parp = 0;
654 sio.bufcount = 8;
655 sio.mcdst = 1;
656 sio.packetsize = 1;
657 sio.rdwr = 0;
658 sio.count = 0;
659
660 // Memcard presence reporting!
661 // Note:
662 // 0x01100 means Memcard is present
663 // 0x1D100 means Memcard is missing.
664
665 const uint port = sio.GetMemcardIndex();
666 const uint slot = sio.activeMemcardSlot[port];
667
668 // forced ejection logic. Technically belongs in the McdIsPresent handler for
669 // the plugin, once the memorycard plugin system is completed.
670 // (ejection is only supported for the default non-multitap cards at this time)
671
672 bool forceEject = false;
673 if( slot == 0 && m_ForceEjectionTimeout[port] )
674 {
675 --m_ForceEjectionTimeout[port];
676 forceEject = true;
677 }
678
679 if( !forceEject && SysPlugins.McdIsPresent( port, slot ) )
680 {
681 sio2.packet.recvVal1 = 0x1100;
682 PAD_LOG("START MEMCARD [port:%d, slot:%d] - Present", port, slot );
683 }
684 else
685 {
686 sio2.packet.recvVal1 = 0x1D100;
687 PAD_LOG("START MEMCARD [port:%d, slot:%d] - Missing", port, slot );
688 }
689
690 SIO_INT();
691 }
692 return;
693 }
694 }
695
696 void sioWrite8(u8 value)
697 {
698 SIO_CommandWrite(value,0);
699 }
700
701 void SIODMAWrite(u8 value)
702 {
703 SIO_CommandWrite(value,1);
704 }
705
706 void sioWriteCtrl16(u16 value) {
707 sio.CtrlReg = value & ~RESET_ERR;
708 if (value & RESET_ERR) sio.StatReg &= ~IRQ;
709 if ((sio.CtrlReg & SIO_RESET) || (!sio.CtrlReg))
710 {
711 sio.mtapst = 0; sio.padst = 0; sio.mcdst = 0; sio.parp = 0;
712 sio.StatReg = TX_RDY | TX_EMPTY;
713 psxRegs.interrupt &= ~(1<<IopEvt_SIO);
714 }
715 }
716
717 void SIO_FORCEINLINE sioInterrupt() {
718 PAD_LOG("Sio Interrupt");
719 sio.StatReg|= IRQ;
720 psxHu32(0x1070)|=0x80;
721 }
722
723 void SaveStateBase::sioFreeze()
724 {
725 // CRCs for memory cards.
726 u64 m_mcdCRCs[2][8];
727
728 FreezeTag( "sio" );
729 Freeze( sio );
730
731 // TODO : This stuff should all be moved to the memorycard plugin eventually,
732 // but that requires adding memorycard plugin to the savestate, and I'm not in
733 // the mood to do that (let's plan it for 0.9.8) --air
734
735 // Note: The Ejection system only works for the default non-multitap MemoryCards
736 // only. This is because it could become very (very!) slow to do a full CRC check
737 // on multiple 32 or 64 meg carts. I have chosen to save
738
739 if( IsSaving() )
740 {
741 for( uint port=0; port<2; ++port )
742 //for( uint slot=0; slot<4; ++slot )
743 {
744 const uint slot = 0; // see above comment about multitap slowness
745 m_mcdCRCs[port][slot] = SysPlugins.McdGetCRC( port, slot );
746 }
747 }
748
749 Freeze( m_mcdCRCs );
750
751 if( IsLoading() && EmuConfig.McdEnableEjection )
752 {
753 // Notes on the ForceEjectionTimeout:
754 // * TOTA works with values as low as 20 here.
755 // It "times out" with values around 1800 (forces user to check the memcard
756 // twice to find it). Other games could be different. :|
757 //
758 // * At 64: Disgaea 1 and 2, and Grandia 2 end up displaying a quick "no memcard!"
759 // notice before finding the memorycard and re-enumerating it. A very minor
760 // annoyance, but no breakages.
761
762 // * GuitarHero will break completely with almost any value here, by design, because
763 // it has a "rule" that the memcard should never be ejected during a song. So by
764 // ejecting it, the game freezes (which is actually good emulation, but annoying!)
765
766 for( uint port=0; port<2; ++port )
767 //for( int slot=0; slot<4; ++slot )
768 {
769 const uint slot = 0; // see above comment about multitap slowness
770 u64 newCRC = SysPlugins.McdGetCRC( port, slot );
771 if( newCRC != m_mcdCRCs[port][slot] )
772 {
773 //m_mcdCRCs[port][slot] = newCRC;
774 m_ForceEjectionTimeout[port] = 128;
775 }
776 }
777 }
778 }
779

  ViewVC Help
Powered by ViewVC 1.1.22