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

Annotation of /trunk/pcsx2/Sio.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide 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 william 31 /* 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