drc: initial cop2/gte implementation (works, mostly)
[pcsx_rearmed.git] / libpcsxcore / sio.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. *
18 ***************************************************************************/
19
20/*
21* SIO functions.
22*/
23
24#include "sio.h"
25#include <sys/stat.h>
26
27// Status Flags
28#define TX_RDY 0x0001
29#define RX_RDY 0x0002
30#define TX_EMPTY 0x0004
31#define PARITY_ERR 0x0008
32#define RX_OVERRUN 0x0010
33#define FRAMING_ERR 0x0020
34#define SYNC_DETECT 0x0040
35#define DSR 0x0080
36#define CTS 0x0100
37#define IRQ 0x0200
38
39// Control Flags
40#define TX_PERM 0x0001
41#define DTR 0x0002
42#define RX_PERM 0x0004
43#define BREAK 0x0008
44#define RESET_ERR 0x0010
45#define RTS 0x0020
46#define SIO_RESET 0x0040
47
48// *** FOR WORKS ON PADS AND MEMORY CARDS *****
49
50static unsigned char buf[256];
51unsigned char cardh[4] = { 0x00, 0x00, 0x5a, 0x5d };
52
53// Transfer Ready and the Buffer is Empty
54// static unsigned short StatReg = 0x002b;
55static unsigned short StatReg = TX_RDY | TX_EMPTY;
56static unsigned short ModeReg;
57static unsigned short CtrlReg;
58static unsigned short BaudReg;
59
60static unsigned int bufcount;
61static unsigned int parp;
62static unsigned int mcdst, rdwr;
63static unsigned char adrH, adrL;
64static unsigned int padst;
65
66char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];
67
68// clk cycle byte
69// 4us * 8bits = (PSXCLK / 1000000) * 32; (linuzappz)
70// TODO: add SioModePrescaler and BaudReg
71static inline void SIO_INT() {
72 if (!Config.Sio) {
73 psxRegs.interrupt |= 0x80;
74 psxRegs.intCycle[7 + 1] = 400;
75 psxRegs.intCycle[7] = psxRegs.cycle;
76 }
77}
78
79void sioWrite8(unsigned char value) {
80#ifdef PAD_LOG
81 PAD_LOG("sio write8 %x\n", value);
82#endif
83 switch (padst) {
84 case 1: SIO_INT();
85 if ((value & 0x40) == 0x40) {
86 padst = 2; parp = 1;
87 if (!Config.UseNet) {
88 switch (CtrlReg & 0x2002) {
89 case 0x0002:
90 buf[parp] = PAD1_poll(value);
91 break;
92 case 0x2002:
93 buf[parp] = PAD2_poll(value);
94 break;
95 }
96 }/* else {
97// SysPrintf("%x: %x, %x, %x, %x\n", CtrlReg&0x2002, buf[2], buf[3], buf[4], buf[5]);
98 }*/
99
100 if (!(buf[parp] & 0x0f)) {
101 bufcount = 2 + 32;
102 } else {
103 bufcount = 2 + (buf[parp] & 0x0f) * 2;
104 }
105 if (buf[parp] == 0x41) {
106 switch (value) {
107 case 0x43:
108 buf[1] = 0x43;
109 break;
110 case 0x45:
111 buf[1] = 0xf3;
112 break;
113 }
114 }
115 }
116 else padst = 0;
117 return;
118 case 2:
119 parp++;
120/* if (buf[1] == 0x45) {
121 buf[parp] = 0;
122 SIO_INT();
123 return;
124 }*/
125 if (!Config.UseNet) {
126 switch (CtrlReg & 0x2002) {
127 case 0x0002: buf[parp] = PAD1_poll(value); break;
128 case 0x2002: buf[parp] = PAD2_poll(value); break;
129 }
130 }
131
132 if (parp == bufcount) { padst = 0; return; }
133 SIO_INT();
134 return;
135 }
136
137 switch (mcdst) {
138 case 1:
139 SIO_INT();
140 if (rdwr) { parp++; return; }
141 parp = 1;
142 switch (value) {
143 case 0x52: rdwr = 1; break;
144 case 0x57: rdwr = 2; break;
145 default: mcdst = 0;
146 }
147 return;
148 case 2: // address H
149 SIO_INT();
150 adrH = value;
151 *buf = 0;
152 parp = 0;
153 bufcount = 1;
154 mcdst = 3;
155 return;
156 case 3: // address L
157 SIO_INT();
158 adrL = value;
159 *buf = adrH;
160 parp = 0;
161 bufcount = 1;
162 mcdst = 4;
163 return;
164 case 4:
165 SIO_INT();
166 parp = 0;
167 switch (rdwr) {
168 case 1: // read
169 buf[0] = 0x5c;
170 buf[1] = 0x5d;
171 buf[2] = adrH;
172 buf[3] = adrL;
173 switch (CtrlReg & 0x2002) {
174 case 0x0002:
175 memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128);
176 break;
177 case 0x2002:
178 memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128);
179 break;
180 }
181 {
182 char xor = 0;
183 int i;
184 for (i = 2; i < 128 + 4; i++)
185 xor ^= buf[i];
186 buf[132] = xor;
187 }
188 buf[133] = 0x47;
189 bufcount = 133;
190 break;
191 case 2: // write
192 buf[0] = adrL;
193 buf[1] = value;
194 buf[129] = 0x5c;
195 buf[130] = 0x5d;
196 buf[131] = 0x47;
197 bufcount = 131;
198 break;
199 }
200 mcdst = 5;
201 return;
202 case 5:
203 parp++;
204 if (rdwr == 2) {
205 if (parp < 128) buf[parp + 1] = value;
206 }
207 SIO_INT();
208 return;
209 }
210
211 switch (value) {
212 case 0x01: // start pad
213 StatReg |= RX_RDY; // Transfer is Ready
214
215 if (!Config.UseNet) {
216 switch (CtrlReg & 0x2002) {
217 case 0x0002: buf[0] = PAD1_startPoll(1); break;
218 case 0x2002: buf[0] = PAD2_startPoll(2); break;
219 }
220 } else {
221 if ((CtrlReg & 0x2002) == 0x0002) {
222 int i, j;
223
224 PAD1_startPoll(1);
225 buf[0] = 0;
226 buf[1] = PAD1_poll(0x42);
227 if (!(buf[1] & 0x0f)) {
228 bufcount = 32;
229 } else {
230 bufcount = (buf[1] & 0x0f) * 2;
231 }
232 buf[2] = PAD1_poll(0);
233 i = 3;
234 j = bufcount;
235 while (j--) {
236 buf[i++] = PAD1_poll(0);
237 }
238 bufcount+= 3;
239
240 if (NET_sendPadData(buf, bufcount) == -1)
241 netError();
242
243 if (NET_recvPadData(buf, 1) == -1)
244 netError();
245 if (NET_recvPadData(buf + 128, 2) == -1)
246 netError();
247 } else {
248 memcpy(buf, buf + 128, 32);
249 }
250 }
251
252 bufcount = 2;
253 parp = 0;
254 padst = 1;
255 SIO_INT();
256 return;
257 case 0x81: // start memcard
258 StatReg |= RX_RDY;
259 memcpy(buf, cardh, 4);
260 parp = 0;
261 bufcount = 3;
262 mcdst = 1;
263 rdwr = 0;
264 SIO_INT();
265 return;
266 }
267}
268
269void sioWriteStat16(unsigned short value) {
270}
271
272void sioWriteMode16(unsigned short value) {
273 ModeReg = value;
274}
275
276void sioWriteCtrl16(unsigned short value) {
277 CtrlReg = value & ~RESET_ERR;
278 if (value & RESET_ERR) StatReg &= ~IRQ;
279 if ((CtrlReg & SIO_RESET) || (!CtrlReg)) {
280 padst = 0; mcdst = 0; parp = 0;
281 StatReg = TX_RDY | TX_EMPTY;
282 psxRegs.interrupt &= ~0x80;
283 }
284}
285
286void sioWriteBaud16(unsigned short value) {
287 BaudReg = value;
288}
289
290unsigned char sioRead8() {
291 unsigned char ret = 0;
292
293 if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) {
294// StatReg &= ~RX_OVERRUN;
295 ret = buf[parp];
296 if (parp == bufcount) {
297 StatReg &= ~RX_RDY; // Receive is not Ready now
298 if (mcdst == 5) {
299 mcdst = 0;
300 if (rdwr == 2) {
301 switch (CtrlReg & 0x2002) {
302 case 0x0002:
303 memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
304 SaveMcd(Config.Mcd1, Mcd1Data, (adrL | (adrH << 8)) * 128, 128);
305 break;
306 case 0x2002:
307 memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
308 SaveMcd(Config.Mcd2, Mcd2Data, (adrL | (adrH << 8)) * 128, 128);
309 break;
310 }
311 }
312 }
313 if (padst == 2) padst = 0;
314 if (mcdst == 1) {
315 mcdst = 2;
316 StatReg|= RX_RDY;
317 }
318 }
319 }
320
321#ifdef PAD_LOG
322 PAD_LOG("sio read8 ;ret = %x\n", ret);
323#endif
324 return ret;
325}
326
327unsigned short sioReadStat16() {
328 return StatReg;
329}
330
331unsigned short sioReadMode16() {
332 return ModeReg;
333}
334
335unsigned short sioReadCtrl16() {
336 return CtrlReg;
337}
338
339unsigned short sioReadBaud16() {
340 return BaudReg;
341}
342
343void netError() {
344 ClosePlugins();
345 SysMessage(_("Connection closed!\n"));
346
347 CdromId[0] = '\0';
348 CdromLabel[0] = '\0';
349
350 SysRunGui();
351}
352
353void sioInterrupt() {
354#ifdef PAD_LOG
355 PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
356#endif
357// SysPrintf("Sio Interrupt\n");
358 StatReg |= IRQ;
359 psxHu32ref(0x1070) |= SWAPu32(0x80);
360}
361
362void LoadMcd(int mcd, char *str) {
363 FILE *f;
364 char *data = NULL;
365
366 if (mcd == 1) data = Mcd1Data;
367 if (mcd == 2) data = Mcd2Data;
368
369 if (*str == 0) {
370 sprintf(str, "memcards/card%d.mcd", mcd);
371 SysPrintf(_("No memory card value was specified - creating a default card %s\n"), str);
372 }
373 f = fopen(str, "rb");
374 if (f == NULL) {
375 SysPrintf(_("The memory card %s doesn't exist - creating it\n"), str);
376 CreateMcd(str);
377 f = fopen(str, "rb");
378 if (f != NULL) {
379 struct stat buf;
380
381 if (stat(str, &buf) != -1) {
382 if (buf.st_size == MCD_SIZE + 64)
383 fseek(f, 64, SEEK_SET);
384 else if(buf.st_size == MCD_SIZE + 3904)
385 fseek(f, 3904, SEEK_SET);
386 }
387 fread(data, 1, MCD_SIZE, f);
388 fclose(f);
389 }
390 else
391 SysMessage(_("Memory card %s failed to load!\n"), str);
392 }
393 else {
394 struct stat buf;
395 SysPrintf(_("Loading memory card %s\n"), str);
396 if (stat(str, &buf) != -1) {
397 if (buf.st_size == MCD_SIZE + 64)
398 fseek(f, 64, SEEK_SET);
399 else if(buf.st_size == MCD_SIZE + 3904)
400 fseek(f, 3904, SEEK_SET);
401 }
402 fread(data, 1, MCD_SIZE, f);
403 fclose(f);
404 }
405}
406
407void LoadMcds(char *mcd1, char *mcd2) {
408 LoadMcd(1, mcd1);
409 LoadMcd(2, mcd2);
410}
411
412void SaveMcd(char *mcd, char *data, uint32_t adr, int size) {
413 FILE *f;
414
415 f = fopen(mcd, "r+b");
416 if (f != NULL) {
417 struct stat buf;
418
419 if (stat(mcd, &buf) != -1) {
420 if (buf.st_size == MCD_SIZE + 64)
421 fseek(f, adr + 64, SEEK_SET);
422 else if (buf.st_size == MCD_SIZE + 3904)
423 fseek(f, adr + 3904, SEEK_SET);
424 else
425 fseek(f, adr, SEEK_SET);
426 } else
427 fseek(f, adr, SEEK_SET);
428
429 fwrite(data + adr, 1, size, f);
430 fclose(f);
431 return;
432 }
433
434#if 0
435 // try to create it again if we can't open it
436 f = fopen(mcd, "wb");
437 if (f != NULL) {
438 fwrite(data, 1, MCD_SIZE, f);
439 fclose(f);
440 }
441#endif
442
443 ConvertMcd(mcd, data);
444}
445
446void CreateMcd(char *mcd) {
447 FILE *f;
448 struct stat buf;
449 int s = MCD_SIZE;
450 int i = 0, j;
451
452 f = fopen(mcd, "wb");
453 if (f == NULL)
454 return;
455
456 if (stat(mcd, &buf) != -1) {
457 if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
458 s = s + 3904;
459 fputc('1', f);
460 s--;
461 fputc('2', f);
462 s--;
463 fputc('3', f);
464 s--;
465 fputc('-', f);
466 s--;
467 fputc('4', f);
468 s--;
469 fputc('5', f);
470 s--;
471 fputc('6', f);
472 s--;
473 fputc('-', f);
474 s--;
475 fputc('S', f);
476 s--;
477 fputc('T', f);
478 s--;
479 fputc('D', f);
480 s--;
481 for (i = 0; i < 7; i++) {
482 fputc(0, f);
483 s--;
484 }
485 fputc(1, f);
486 s--;
487 fputc(0, f);
488 s--;
489 fputc(1, f);
490 s--;
491 fputc('M', f);
492 s--;
493 fputc('Q', f);
494 s--;
495 for (i = 0; i < 14; i++) {
496 fputc(0xa0, f);
497 s--;
498 }
499 fputc(0, f);
500 s--;
501 fputc(0xff, f);
502 while (s-- > (MCD_SIZE + 1))
503 fputc(0, f);
504 } else if ((buf.st_size == MCD_SIZE + 64) || strstr(mcd, ".mem") || strstr(mcd, ".vgs")) {
505 s = s + 64;
506 fputc('V', f);
507 s--;
508 fputc('g', f);
509 s--;
510 fputc('s', f);
511 s--;
512 fputc('M', f);
513 s--;
514 for (i = 0; i < 3; i++) {
515 fputc(1, f);
516 s--;
517 fputc(0, f);
518 s--;
519 fputc(0, f);
520 s--;
521 fputc(0, f);
522 s--;
523 }
524 fputc(0, f);
525 s--;
526 fputc(2, f);
527 while (s-- > (MCD_SIZE + 1))
528 fputc(0, f);
529 }
530 }
531 fputc('M', f);
532 s--;
533 fputc('C', f);
534 s--;
535 while (s-- > (MCD_SIZE - 127))
536 fputc(0, f);
537 fputc(0xe, f);
538 s--;
539
540 for (i = 0; i < 15; i++) { // 15 blocks
541 fputc(0xa0, f);
542 s--;
543 fputc(0x00, f);
544 s--;
545 fputc(0x00, f);
546 s--;
547 fputc(0x00, f);
548 s--;
549 fputc(0x00, f);
550 s--;
551 fputc(0x00, f);
552 s--;
553 fputc(0x00, f);
554 s--;
555 fputc(0x00, f);
556 s--;
557 fputc(0xff, f);
558 s--;
559 fputc(0xff, f);
560 s--;
561 for (j = 0; j < 117; j++) {
562 fputc(0x00, f);
563 s--;
564 }
565 fputc(0xa0, f);
566 s--;
567 }
568
569 for (i = 0; i < 20; i++) {
570 fputc(0xff, f);
571 s--;
572 fputc(0xff, f);
573 s--;
574 fputc(0xff, f);
575 s--;
576 fputc(0xff, f);
577 s--;
578 fputc(0x00, f);
579 s--;
580 fputc(0x00, f);
581 s--;
582 fputc(0x00, f);
583 s--;
584 fputc(0x00, f);
585 s--;
586 fputc(0xff, f);
587 s--;
588 fputc(0xff, f);
589 s--;
590 for (j = 0; j < 118; j++) {
591 fputc(0x00, f);
592 s--;
593 }
594 }
595
596 while ((s--) >= 0)
597 fputc(0, f);
598
599 fclose(f);
600}
601
602void ConvertMcd(char *mcd, char *data) {
603 FILE *f;
604 int i = 0;
605 int s = MCD_SIZE;
606
607 if (strstr(mcd, ".gme")) {
608 f = fopen(mcd, "wb");
609 if (f != NULL) {
610 fwrite(data - 3904, 1, MCD_SIZE + 3904, f);
611 fclose(f);
612 }
613 f = fopen(mcd, "r+");
614 s = s + 3904;
615 fputc('1', f); s--;
616 fputc('2', f); s--;
617 fputc('3', f); s--;
618 fputc('-', f); s--;
619 fputc('4', f); s--;
620 fputc('5', f); s--;
621 fputc('6', f); s--;
622 fputc('-', f); s--;
623 fputc('S', f); s--;
624 fputc('T', f); s--;
625 fputc('D', f); s--;
626 for (i = 0; i < 7; i++) {
627 fputc(0, f); s--;
628 }
629 fputc(1, f); s--;
630 fputc(0, f); s--;
631 fputc(1, f); s--;
632 fputc('M', f); s--;
633 fputc('Q', f); s--;
634 for(i=0;i<14;i++) {
635 fputc(0xa0, f); s--;
636 }
637 fputc(0, f); s--;
638 fputc(0xff, f);
639 while (s-- > (MCD_SIZE+1)) fputc(0, f);
640 fclose(f);
641 } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) {
642 f = fopen(mcd, "wb");
643 if (f != NULL) {
644 fwrite(data-64, 1, MCD_SIZE+64, f);
645 fclose(f);
646 }
647 f = fopen(mcd, "r+");
648 s = s + 64;
649 fputc('V', f); s--;
650 fputc('g', f); s--;
651 fputc('s', f); s--;
652 fputc('M', f); s--;
653 for(i=0;i<3;i++) {
654 fputc(1, f); s--;
655 fputc(0, f); s--;
656 fputc(0, f); s--;
657 fputc(0, f); s--;
658 }
659 fputc(0, f); s--;
660 fputc(2, f);
661 while (s-- > (MCD_SIZE+1)) fputc(0, f);
662 fclose(f);
663 } else {
664 f = fopen(mcd, "wb");
665 if (f != NULL) {
666 fwrite(data, 1, MCD_SIZE, f);
667 fclose(f);
668 }
669 }
670}
671
672void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) {
673 unsigned char *data = NULL, *ptr, *str, *sstr;
674 unsigned short clut[16];
675 unsigned short c;
676 int i, x;
677
678 memset(Info, 0, sizeof(McdBlock));
679
680 if (mcd == 1) data = Mcd1Data;
681 if (mcd == 2) data = Mcd2Data;
682
683 ptr = data + block * 8192 + 2;
684
685 Info->IconCount = *ptr & 0x3;
686
687 ptr += 2;
688
689 x = 0;
690
691 str = Info->Title;
692 sstr = Info->sTitle;
693
694 for (i = 0; i < 48; i++) {
695 c = *(ptr) << 8;
696 c |= *(ptr + 1);
697 if (!c) break;
698
699 // Convert ASCII characters to half-width
700 if (c >= 0x8281 && c <= 0x829A)
701 c = (c - 0x8281) + 'a';
702 else if (c >= 0x824F && c <= 0x827A)
703 c = (c - 0x824F) + '0';
704 else if (c == 0x8140) c = ' ';
705 else if (c == 0x8143) c = ',';
706 else if (c == 0x8144) c = '.';
707 else if (c == 0x8146) c = ':';
708 else if (c == 0x8147) c = ';';
709 else if (c == 0x8148) c = '?';
710 else if (c == 0x8149) c = '!';
711 else if (c == 0x815E) c = '/';
712 else if (c == 0x8168) c = '"';
713 else if (c == 0x8169) c = '(';
714 else if (c == 0x816A) c = ')';
715 else if (c == 0x816D) c = '[';
716 else if (c == 0x816E) c = ']';
717 else if (c == 0x817C) c = '-';
718 else {
719 str[i] = ' ';
720 sstr[x++] = *ptr++; sstr[x++] = *ptr++;
721 continue;
722 }
723
724 str[i] = sstr[x++] = c;
725 ptr += 2;
726 }
727
728 trim(str);
729 trim(sstr);
730
731 ptr = data + block * 8192 + 0x60; // icon palette data
732
733 for (i = 0; i < 16; i++) {
734 clut[i] = *((unsigned short *)ptr);
735 ptr += 2;
736 }
737
738 for (i = 0; i < Info->IconCount; i++) {
739 short *icon = &Info->Icon[i * 16 * 16];
740
741 ptr = data + block * 8192 + 128 + 128 * i; // icon data
742
743 for (x = 0; x < 16 * 16; x++) {
744 icon[x++] = clut[*ptr & 0xf];
745 icon[x] = clut[*ptr >> 4];
746 ptr++;
747 }
748 }
749
750 ptr = data + block * 128;
751
752 Info->Flags = *ptr;
753
754 ptr += 0xa;
755 strncpy(Info->ID, ptr, 12);
756 ptr += 12;
757 strncpy(Info->Name, ptr, 16);
758}
759
760int sioFreeze(gzFile f, int Mode) {
761 gzfreeze(buf, sizeof(buf));
762 gzfreeze(&StatReg, sizeof(StatReg));
763 gzfreeze(&ModeReg, sizeof(ModeReg));
764 gzfreeze(&CtrlReg, sizeof(CtrlReg));
765 gzfreeze(&BaudReg, sizeof(BaudReg));
766 gzfreeze(&bufcount, sizeof(bufcount));
767 gzfreeze(&parp, sizeof(parp));
768 gzfreeze(&mcdst, sizeof(mcdst));
769 gzfreeze(&rdwr, sizeof(rdwr));
770 gzfreeze(&adrH, sizeof(adrH));
771 gzfreeze(&adrL, sizeof(adrL));
772 gzfreeze(&padst, sizeof(padst));
773
774 return 0;
775}