1 /* Mednafen - Multi-system Emulator
2  *
3  * This program is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17 
18 // I could find no other commands than 'R', 'W', and 'S' (not sure what 'S' is for, however)
19 
20 #include "../psx.h"
21 #include "../frontio.h"
22 #include "memcard.h"
23 
24 class InputDevice_Memcard : public InputDevice
25 {
26    public:
27 
28       InputDevice_Memcard();
29       virtual ~InputDevice_Memcard();
30 
31       virtual void Power(void);
32       virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
33 
34       //
35       //
36       //
37       virtual void SetDTR(bool new_dtr);
38       virtual bool GetDSR(void);
39       virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
40 
41       //
42       //
43       virtual uint8 *GetNVData(void);
44       virtual uint32 GetNVSize(void);
45       virtual void ReadNV(uint8 *buffer, uint32 offset, uint32 size);
46       virtual void WriteNV(const uint8 *buffer, uint32 offset, uint32 size);
47 
48       virtual uint64 GetNVDirtyCount(void);
49       virtual void ResetNVDirtyCount(void);
50 
51       void Format(void);
52 
53    private:
54 
55       bool presence_new;
56 
57       uint8 card_data[1 << 17];
58       uint8 rw_buffer[128];
59       uint8 write_xor;
60 
61       //
62       // Used to avoid saving unused memory cards' card data in save states.
63       // Set to false on object initialization, set to true when data is written to card_data that differs
64       // from existing data(either from loading a memory card saved to disk, or from a game writing to the memory card).
65       //
66       // Save and load its state to/from save states.
67       //
68       bool data_used;
69 
70       //
71       // Do not save dirty_count in save states!
72       //
73       uint64 dirty_count;
74 
75       bool dtr;
76       int32 command_phase;
77       uint32 bitpos;
78       uint8 receive_buffer;
79 
80       uint8 command;
81       uint16 addr;
82       uint8 calced_xor;
83 
84       uint8 transmit_buffer;
85       uint32 transmit_count;
86 };
87 
Format(void)88 void InputDevice_Memcard::Format(void)
89 {
90    memset(card_data, 0x00, sizeof(card_data));
91 
92    card_data[0x00] = 0x4D;
93    card_data[0x01] = 0x43;
94    card_data[0x7F] = 0x0E;
95 
96    for(unsigned int A = 0x80; A < 0x800; A += 0x80)
97    {
98       card_data[A + 0x00] = 0xA0;
99       card_data[A + 0x08] = 0xFF;
100       card_data[A + 0x09] = 0xFF;
101       card_data[A + 0x7F] = 0xA0;
102    }
103 
104    for(unsigned int A = 0x0800; A < 0x1200; A += 0x80)
105    {
106       card_data[A + 0x00] = 0xFF;
107       card_data[A + 0x01] = 0xFF;
108       card_data[A + 0x02] = 0xFF;
109       card_data[A + 0x03] = 0xFF;
110       card_data[A + 0x08] = 0xFF;
111       card_data[A + 0x09] = 0xFF;
112    }
113 }
114 
InputDevice_Memcard()115 InputDevice_Memcard::InputDevice_Memcard()
116 {
117    Power();
118 
119    data_used = false;
120    dirty_count = 0;
121 
122    // Init memcard as formatted.
123    assert(sizeof(card_data) == (1 << 17));
124    Format();
125 }
126 
~InputDevice_Memcard()127 InputDevice_Memcard::~InputDevice_Memcard()
128 {
129 
130 }
131 
Power(void)132 void InputDevice_Memcard::Power(void)
133 {
134    dtr = 0;
135 
136    //buttons[0] = buttons[1] = 0;
137 
138    command_phase = 0;
139 
140    bitpos = 0;
141 
142    receive_buffer = 0;
143 
144    command = 0;
145 
146    transmit_buffer = 0;
147 
148    transmit_count = 0;
149 
150    addr = 0;
151 
152    presence_new = true;
153 }
154 
StateAction(StateMem * sm,int load,int data_only,const char * section_name)155 int InputDevice_Memcard::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
156 {
157    // Don't save dirty_count.
158    SFORMAT StateRegs[] =
159    {
160       SFVAR(presence_new),
161 
162       SFARRAY(rw_buffer, sizeof(rw_buffer)),
163       SFVAR(write_xor),
164 
165       SFVAR(dtr),
166       SFVAR(command_phase),
167       SFVAR(bitpos),
168       SFVAR(receive_buffer),
169 
170       SFVAR(command),
171       SFVAR(addr),
172       SFVAR(calced_xor),
173 
174       SFVAR(transmit_buffer),
175       SFVAR(transmit_count),
176 
177       SFVAR(data_used),
178 
179       SFEND
180    };
181 
182    SFORMAT CD_StateRegs[] =
183    {
184       SFARRAY(card_data, sizeof(card_data)),
185       SFEND
186    };
187    int ret = 1;
188 
189    if(MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name) != 0)
190    {
191       //printf("%s data_used=%d\n", section_name, data_used);
192       if(data_used)
193       {
194          std::string tmp_name = std::string(section_name) + "_DT";
195 
196          ret &= MDFNSS_StateAction(sm, load, data_only, CD_StateRegs, tmp_name.c_str());
197       }
198 
199       if(load)
200       {
201          if(data_used)
202             dirty_count++;
203       }
204    }
205    else
206       ret = 0;
207 
208    return(ret);
209 }
210 
SetDTR(bool new_dtr)211 void InputDevice_Memcard::SetDTR(bool new_dtr)
212 {
213    if(!dtr && new_dtr)
214    {
215       command_phase = 0;
216       bitpos = 0;
217       transmit_count = 0;
218    }
219    else if(dtr && !new_dtr)
220    {
221       if(command_phase > 0)
222          PSX_WARNING("[MCR] Communication aborted on phase %d", command_phase);
223    }
224    dtr = new_dtr;
225 }
226 
GetDSR(void)227 bool InputDevice_Memcard::GetDSR(void)
228 {
229    if(!dtr)
230       return(0);
231 
232    if(!bitpos && transmit_count)
233       return(1);
234 
235    return(0);
236 }
237 
Clock(bool TxD,int32 & dsr_pulse_delay)238 bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
239 {
240    bool ret = 1;
241 
242    dsr_pulse_delay = 0;
243 
244    if(!dtr)
245       return(1);
246 
247    if(transmit_count)
248       ret = (transmit_buffer >> bitpos) & 1;
249 
250    receive_buffer &= ~(1 << bitpos);
251    receive_buffer |= TxD << bitpos;
252    bitpos = (bitpos + 1) & 0x7;
253 
254    if(!bitpos)
255    {
256       //if(command_phase > 0 || transmit_count)
257       // printf("[MCRDATA] Received_data=0x%02x, Sent_data=0x%02x\n", receive_buffer, transmit_buffer);
258 
259       if(transmit_count)
260       {
261          transmit_count--;
262       }
263 
264       if (command_phase >= 1024 && command_phase <= 1151)
265       {
266          // Transmit actual 128 bytes data
267          transmit_buffer = card_data[(addr << 7) + (command_phase - 1024)];
268          calced_xor ^= transmit_buffer;
269          transmit_count = 1;
270          command_phase++;
271       }
272       else if (command_phase >= 2048 && command_phase <= 2175)
273       {
274          calced_xor ^= receive_buffer;
275          rw_buffer[command_phase - 2048] = receive_buffer;
276 
277          transmit_buffer = receive_buffer;
278          transmit_count = 1;
279          command_phase++;
280       }
281       else
282          switch(command_phase)
283          {
284             case 0:
285                if(receive_buffer != 0x81)
286                   command_phase = -1;
287                else
288                {
289                   //printf("[MCR] Device selected\n");
290                   transmit_buffer = presence_new ? 0x08 : 0x00;
291                   transmit_count = 1;
292                   command_phase++;
293                }
294                break;
295 
296             case 1:
297                command = receive_buffer;
298                //printf("[MCR] Command received: %c\n", command);
299                if(command == 'R' || command == 'W')
300                {
301                   command_phase++;
302                   transmit_buffer = 0x5A;
303                   transmit_count = 1;
304                }
305                else
306                {
307                   if(command == 'S')
308                   {
309                      PSX_WARNING("[MCR] Memcard S command unsupported.");
310                   }
311 
312                   command_phase = -1;
313                   transmit_buffer = 0;
314                   transmit_count = 0;
315                }
316                break;
317 
318             case 2:
319                transmit_buffer = 0x5D;
320                transmit_count = 1;
321                command_phase++;
322                break;
323 
324             case 3:
325                transmit_buffer = 0x00;
326                transmit_count = 1;
327                if(command == 'R')
328                   command_phase = 1000;
329                else if(command == 'W')
330                   command_phase = 2000;
331                break;
332 
333                //
334                // Read
335                //
336             case 1000:
337                addr = receive_buffer << 8;
338                transmit_buffer = receive_buffer;
339                transmit_count = 1;
340                command_phase++;
341                break;
342 
343             case 1001:
344                addr |= receive_buffer & 0xFF;
345                transmit_buffer = '\\';
346                transmit_count = 1;
347                command_phase++;
348                break;
349 
350             case 1002:
351                //printf("[MCR]   READ ADDR=0x%04x\n", addr);
352                if(addr >= (sizeof(card_data) >> 7))
353                   addr = 0xFFFF;
354 
355                calced_xor = 0;
356                transmit_buffer = ']';
357                transmit_count = 1;
358                command_phase++;
359 
360                // TODO: enable this code(or something like it) when CPU instruction timing is a bit better.
361                //
362                //dsr_pulse_delay = 32000;
363                //goto SkipDPD;
364                //
365 
366                break;
367 
368             case 1003:
369                transmit_buffer = addr >> 8;
370                calced_xor ^= transmit_buffer;
371                transmit_count = 1;
372                command_phase++;
373                break;
374 
375             case 1004:
376                transmit_buffer = addr & 0xFF;
377                calced_xor ^= transmit_buffer;
378 
379                if(addr == 0xFFFF)
380                {
381                   transmit_count = 1;
382                   command_phase = -1;
383                }
384                else
385                {
386                   transmit_count = 1;
387                   command_phase = 1024;
388                }
389                break;
390 
391 
392 
393                // XOR
394             case (1024 + 128):
395                transmit_buffer = calced_xor;
396                transmit_count = 1;
397                command_phase++;
398                break;
399 
400                // End flag
401             case (1024 + 129):
402                transmit_buffer = 'G';
403                transmit_count = 1;
404                command_phase = -1;
405                break;
406 
407                //
408                // Write
409                //
410             case 2000:
411                calced_xor = receive_buffer;
412                addr = receive_buffer << 8;
413                transmit_buffer = receive_buffer;
414                transmit_count = 1;
415                command_phase++;
416                break;
417 
418             case 2001:
419                calced_xor ^= receive_buffer;
420                addr |= receive_buffer & 0xFF;
421                //printf("[MCR]   WRITE ADDR=0x%04x\n", addr);
422                transmit_buffer = receive_buffer;
423                transmit_count = 1;
424                command_phase = 2048;
425                break;
426             case (2048 + 128):	// XOR
427                write_xor = receive_buffer;
428                transmit_buffer = '\\';
429                transmit_count = 1;
430                command_phase++;
431                break;
432 
433             case (2048 + 129):
434                transmit_buffer = ']';
435                transmit_count = 1;
436                command_phase++;
437                break;
438 
439             case (2048 + 130):	// End flag
440                //printf("[MCR] Write End.  Actual_XOR=0x%02x, CW_XOR=0x%02x\n", calced_xor, write_xor);
441 
442                if(calced_xor != write_xor)
443                   transmit_buffer = 'N';
444                else if(addr >= (sizeof(card_data) >> 7))
445                   transmit_buffer = 0xFF;
446                else
447                {
448                   transmit_buffer = 'G';
449                   presence_new = false;
450 
451                   // If the current data is different from the data to be written, increment the dirty count.
452                   // memcpy()'ing over to card_data is also conditionalized here for a slight optimization.
453                   if(memcmp(&card_data[addr << 7], rw_buffer, 128))
454                   {
455                      memcpy(&card_data[addr << 7], rw_buffer, 128);
456                      dirty_count++;
457                      data_used = true;
458                   }
459                }
460 
461                transmit_count = 1;
462                command_phase = -1;
463                break;
464 
465          }
466 
467       //if(command_phase != -1 || transmit_count)
468       // printf("[MCR] Receive: 0x%02x, Send: 0x%02x -- %d\n", receive_buffer, transmit_buffer, command_phase);
469    }
470 
471    if(!bitpos && transmit_count)
472       dsr_pulse_delay = 0x100;
473 
474    //SkipDPD: ;
475 
476    return(ret);
477 }
478 
GetNVData(void)479 uint8 *InputDevice_Memcard::GetNVData(void)
480 {
481    return card_data;
482 }
483 
GetNVSize(void)484 uint32 InputDevice_Memcard::GetNVSize(void)
485 {
486    return(sizeof(card_data));
487 }
488 
ReadNV(uint8 * buffer,uint32 offset,uint32 size)489 void InputDevice_Memcard::ReadNV(uint8 *buffer, uint32 offset, uint32 size)
490 {
491    while(size--)
492    {
493       *buffer = card_data[offset & (sizeof(card_data) - 1)];
494       buffer++;
495       offset++;
496    }
497 }
498 
WriteNV(const uint8 * buffer,uint32 offset,uint32 size)499 void InputDevice_Memcard::WriteNV(const uint8 *buffer, uint32 offset, uint32 size)
500 {
501    if(size)
502    {
503       dirty_count++;
504    }
505 
506    while(size--)
507    {
508       if(card_data[offset & (sizeof(card_data) - 1)] != *buffer)
509          data_used = true;
510 
511       card_data[offset & (sizeof(card_data) - 1)] = *buffer;
512       buffer++;
513       offset++;
514    }
515 }
516 
GetNVDirtyCount(void)517 uint64 InputDevice_Memcard::GetNVDirtyCount(void)
518 {
519    return(dirty_count);
520 }
521 
ResetNVDirtyCount(void)522 void InputDevice_Memcard::ResetNVDirtyCount(void)
523 {
524    dirty_count = 0;
525 }
526 
527 
Device_Memcard_Create(void)528 InputDevice *Device_Memcard_Create(void)
529 {
530    return new InputDevice_Memcard();
531 }
532 
Device_Memcard_Power(InputDevice * device)533 void Device_Memcard_Power(InputDevice *device)
534 {
535    if (InputDevice_Memcard* memcard = dynamic_cast<InputDevice_Memcard*>(device))
536       memcard->Power();
537 }
538 
Device_Memcard_Format(InputDevice * device)539 void Device_Memcard_Format(InputDevice *device)
540 {
541    if (InputDevice_Memcard* memcard = dynamic_cast<InputDevice_Memcard*>(device))
542       memcard->Format();
543 }
544