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