1 /***************************************************************************
2 * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team *
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. *
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. *
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 ***************************************************************************/
25 #include "psxcounters.h"
26 #include "psxevents.h"
30 #ifdef USE_LIBRETRO_VFS
31 #include <streams/file_stream_transforms.h>
37 #define TX_EMPTY 0x0004
38 #define PARITY_ERR 0x0008
39 #define RX_OVERRUN 0x0010
40 #define FRAMING_ERR 0x0020
41 #define SYNC_DETECT 0x0040
47 #define TX_PERM 0x0001
49 #define RX_PERM 0x0004
51 #define RESET_ERR 0x0010
53 #define SIO_RESET 0x0040
55 // *** FOR WORKS ON PADS AND MEMORY CARDS *****
57 static unsigned char buf[256];
58 static unsigned char cardh1[4] = { 0xff, 0x08, 0x5a, 0x5d };
59 static unsigned char cardh2[4] = { 0xff, 0x08, 0x5a, 0x5d };
61 // Transfer Ready and the Buffer is Empty
62 // static unsigned short StatReg = 0x002b;
63 static unsigned short StatReg = TX_RDY | TX_EMPTY;
64 static unsigned short ModeReg;
65 static unsigned short CtrlReg;
66 static unsigned short BaudReg;
68 static unsigned int bufcount;
69 static unsigned int parp;
70 static unsigned int mcdst, rdwr;
71 static unsigned char adrH, adrL;
72 static unsigned int padst;
74 char Mcd1Data[MCD_SIZE], Mcd2Data[MCD_SIZE];
78 // 4us * 8bits = (PSXCLK / 1000000) * 32; (linuzappz)
79 // TODO: add SioModePrescaler and BaudReg
80 #define SIO_CYCLES 535
82 void sioWrite8(unsigned char value) {
85 s32 framec = psxRegs.cycle - rcnts[3].cycleStart;
86 printf("%d:%03d sio write8 %04x %02x\n", frame_counter,
87 (s32)(framec / (PSXCLK / 60 / 263.0f)), CtrlReg, value);
91 if ((value & 0x40) == 0x40) {
93 switch (CtrlReg & 0x2002) {
95 buf[parp] = PAD1_poll(value, &more_data);
98 buf[parp] = PAD2_poll(value, &more_data);
104 set_event(PSXINT_SIO, SIO_CYCLES);
111 switch (CtrlReg & 0x2002) {
112 case 0x0002: buf[parp] = PAD1_poll(value, &more_data); break;
113 case 0x2002: buf[parp] = PAD2_poll(value, &more_data); break;
118 set_event(PSXINT_SIO, SIO_CYCLES);
125 set_event(PSXINT_SIO, SIO_CYCLES);
126 if (rdwr) { parp++; return; }
129 case 0x52: rdwr = 1; break;
130 case 0x57: rdwr = 2; break;
135 set_event(PSXINT_SIO, SIO_CYCLES);
143 set_event(PSXINT_SIO, SIO_CYCLES);
151 set_event(PSXINT_SIO, SIO_CYCLES);
159 switch (CtrlReg & 0x2002) {
161 memcpy(&buf[4], Mcd1Data + (adrL | (adrH << 8)) * 128, 128);
164 memcpy(&buf[4], Mcd2Data + (adrL | (adrH << 8)) * 128, 128);
170 for (i = 2; i < 128 + 4; i++)
190 if ((rdwr == 1 && parp == 132) ||
191 (rdwr == 2 && parp == 129)) {
192 // clear "new card" flags
193 if (CtrlReg & 0x2000)
199 if (parp < 128) buf[parp + 1] = value;
201 set_event(PSXINT_SIO, SIO_CYCLES);
206 case 0x01: // start pad
207 StatReg |= RX_RDY; // Transfer is Ready
209 switch (CtrlReg & 0x2002) {
210 case 0x0002: buf[0] = PAD1_startPoll(1); break;
211 case 0x2002: buf[0] = PAD2_startPoll(2); break;
216 set_event(PSXINT_SIO, SIO_CYCLES);
218 case 0x81: // start memcard
219 if (CtrlReg & 0x2000)
223 memcpy(buf, cardh2, 4);
229 memcpy(buf, cardh1, 4);
236 set_event(PSXINT_SIO, SIO_CYCLES);
248 void sioWriteStat16(unsigned short value) {
251 void sioWriteMode16(unsigned short value) {
255 void sioWriteCtrl16(unsigned short value) {
256 CtrlReg = value & ~RESET_ERR;
257 if (value & RESET_ERR) StatReg &= ~IRQ;
258 if ((CtrlReg & SIO_RESET) || !(CtrlReg & DTR)) {
259 padst = 0; mcdst = 0; parp = 0;
260 StatReg = TX_RDY | TX_EMPTY;
261 psxRegs.interrupt &= ~(1 << PSXINT_SIO);
265 void sioWriteBaud16(unsigned short value) {
269 unsigned char sioRead8() {
270 unsigned char ret = 0;
272 if ((StatReg & RX_RDY)/* && (CtrlReg & RX_PERM)*/) {
273 // StatReg &= ~RX_OVERRUN;
275 if (parp == bufcount) {
276 StatReg &= ~RX_RDY; // Receive is not Ready now
280 switch (CtrlReg & 0x2002) {
282 memcpy(Mcd1Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
283 SaveMcd(Config.Mcd1, Mcd1Data, (adrL | (adrH << 8)) * 128, 128);
286 memcpy(Mcd2Data + (adrL | (adrH << 8)) * 128, &buf[1], 128);
287 SaveMcd(Config.Mcd2, Mcd2Data, (adrL | (adrH << 8)) * 128, 128);
292 if (padst == 2) padst = 0;
301 s32 framec = psxRegs.cycle - rcnts[3].cycleStart;
302 printf("%d:%03d sio read8 %04x %02x\n", frame_counter,
303 (s32)((float)framec / (PSXCLK / 60 / 263.0f)), CtrlReg, ret);
308 unsigned short sioReadStat16() {
312 unsigned short sioReadMode16() {
316 unsigned short sioReadCtrl16() {
320 unsigned short sioReadBaud16() {
324 void sioInterrupt() {
326 PAD_LOG("Sio Interrupt (CP0.Status = %x)\n", psxRegs.CP0.n.Status);
328 // SysPrintf("Sio Interrupt\n");
329 if (!(StatReg & IRQ)) {
331 psxHu32ref(0x1070) |= SWAPu32(0x80);
335 void LoadMcd(int mcd, char *str) {
339 if (mcd != 1 && mcd != 2)
344 cardh1[1] |= 8; // mark as new
351 McdDisable[mcd - 1] = 0;
353 // memcard1 is handled by libretro
358 if (str == NULL || strcmp(str, "none") == 0) {
359 McdDisable[mcd - 1] = 1;
365 f = fopen(str, "rb");
367 SysPrintf(_("The memory card %s doesn't exist - creating it\n"), str);
369 f = fopen(str, "rb");
373 if (stat(str, &buf) != -1) {
374 if (buf.st_size == MCD_SIZE + 64)
375 fseek(f, 64, SEEK_SET);
376 else if(buf.st_size == MCD_SIZE + 3904)
377 fseek(f, 3904, SEEK_SET);
379 if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
381 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
383 memset(data, 0x00, MCD_SIZE);
388 SysMessage(_("Memory card %s failed to load!\n"), str);
392 SysPrintf(_("Loading memory card %s\n"), str);
393 if (stat(str, &buf) != -1) {
394 if (buf.st_size == MCD_SIZE + 64)
395 fseek(f, 64, SEEK_SET);
396 else if(buf.st_size == MCD_SIZE + 3904)
397 fseek(f, 3904, SEEK_SET);
399 if (fread(data, 1, MCD_SIZE, f) != MCD_SIZE) {
401 SysPrintf(_("File IO error in <%s:%s>.\n"), __FILE__, __func__);
403 memset(data, 0x00, MCD_SIZE);
409 void LoadMcds(char *mcd1, char *mcd2) {
414 void SaveMcd(char *mcd, char *data, uint32_t adr, int size) {
417 if (mcd == NULL || *mcd == 0 || strcmp(mcd, "none") == 0)
420 f = fopen(mcd, "r+b");
424 if (stat(mcd, &buf) != -1) {
425 if (buf.st_size == MCD_SIZE + 64)
426 fseek(f, adr + 64, SEEK_SET);
427 else if (buf.st_size == MCD_SIZE + 3904)
428 fseek(f, adr + 3904, SEEK_SET);
430 fseek(f, adr, SEEK_SET);
432 fseek(f, adr, SEEK_SET);
434 fwrite(data + adr, 1, size, f);
440 // try to create it again if we can't open it
441 f = fopen(mcd, "wb");
443 fwrite(data, 1, MCD_SIZE, f);
448 ConvertMcd(mcd, data);
451 void CreateMcd(char *mcd) {
457 f = fopen(mcd, "wb");
459 SysPrintf("CreateMcd: couldn't open %s\n", mcd);
463 if (stat(mcd, &buf) != -1) {
464 if ((buf.st_size == MCD_SIZE + 3904) || strstr(mcd, ".gme")) {
488 for (i = 0; i < 7; i++) {
502 for (i = 0; i < 14; i++) {
509 while (s-- > (MCD_SIZE + 1))
511 } else if ((buf.st_size == MCD_SIZE + 64) || strstr(mcd, ".mem") || strstr(mcd, ".vgs")) {
521 for (i = 0; i < 3; i++) {
534 while (s-- > (MCD_SIZE + 1))
542 while (s-- > (MCD_SIZE - 127))
547 for (i = 0; i < 15; i++) { // 15 blocks
568 for (j = 0; j < 117; j++) {
576 for (i = 0; i < 20; i++) {
597 for (j = 0; j < 118; j++) {
609 void ConvertMcd(char *mcd, char *data) {
614 if (strstr(mcd, ".gme")) {
615 f = fopen(mcd, "wb");
617 fwrite(data - 3904, 1, MCD_SIZE + 3904, f);
620 f = fopen(mcd, "r+");
621 if (f == NULL) return;
634 for (i = 0; i < 7; i++) {
647 while (s-- > (MCD_SIZE+1)) fputc(0, f);
649 } else if(strstr(mcd, ".mem") || strstr(mcd,".vgs")) {
650 f = fopen(mcd, "wb");
652 fwrite(data-64, 1, MCD_SIZE+64, f);
655 f = fopen(mcd, "r+");
656 if (f == NULL) return;
670 while (s-- > (MCD_SIZE+1)) fputc(0, f);
673 f = fopen(mcd, "wb");
675 fwrite(data, 1, MCD_SIZE, f);
681 void GetMcdBlockInfo(int mcd, int block, McdBlock *Info) {
682 char *data = NULL, *ptr, *str, *sstr;
683 unsigned short clut[16];
687 memset(Info, 0, sizeof(McdBlock));
689 if (mcd != 1 && mcd != 2)
692 if (McdDisable[mcd - 1])
695 if (mcd == 1) data = Mcd1Data;
696 if (mcd == 2) data = Mcd2Data;
698 ptr = data + block * 8192 + 2;
700 Info->IconCount = *ptr & 0x3;
709 for (i = 0; i < 48; i++) {
714 // Convert ASCII characters to half-width
715 if (c >= 0x8281 && c <= 0x829A)
716 c = (c - 0x8281) + 'a';
717 else if (c >= 0x824F && c <= 0x827A)
718 c = (c - 0x824F) + '0';
719 else if (c == 0x8140) c = ' ';
720 else if (c == 0x8143) c = ',';
721 else if (c == 0x8144) c = '.';
722 else if (c == 0x8146) c = ':';
723 else if (c == 0x8147) c = ';';
724 else if (c == 0x8148) c = '?';
725 else if (c == 0x8149) c = '!';
726 else if (c == 0x815E) c = '/';
727 else if (c == 0x8168) c = '"';
728 else if (c == 0x8169) c = '(';
729 else if (c == 0x816A) c = ')';
730 else if (c == 0x816D) c = '[';
731 else if (c == 0x816E) c = ']';
732 else if (c == 0x817C) c = '-';
735 sstr[x++] = *ptr++; sstr[x++] = *ptr++;
739 str[i] = sstr[x++] = c;
746 ptr = data + block * 8192 + 0x60; // icon palette data
748 for (i = 0; i < 16; i++) {
749 clut[i] = *((unsigned short *)ptr);
753 for (i = 0; i < Info->IconCount; i++) {
754 short *icon = &Info->Icon[i * 16 * 16];
756 ptr = data + block * 8192 + 128 + 128 * i; // icon data
758 for (x = 0; x < 16 * 16; x++) {
759 icon[x++] = clut[*ptr & 0xf];
760 icon[x] = clut[*ptr >> 4];
765 ptr = data + block * 128;
770 strncpy(Info->ID, ptr, 12);
772 strncpy(Info->Name, ptr, 16);
775 int sioFreeze(void *f, int Mode) {
776 gzfreeze(buf, sizeof(buf));
777 gzfreeze(&StatReg, sizeof(StatReg));
778 gzfreeze(&ModeReg, sizeof(ModeReg));
779 gzfreeze(&CtrlReg, sizeof(CtrlReg));
780 gzfreeze(&BaudReg, sizeof(BaudReg));
781 gzfreeze(&bufcount, sizeof(bufcount));
782 gzfreeze(&parp, sizeof(parp));
783 gzfreeze(&mcdst, sizeof(mcdst));
784 gzfreeze(&rdwr, sizeof(rdwr));
785 gzfreeze(&adrH, sizeof(adrH));
786 gzfreeze(&adrL, sizeof(adrL));
787 gzfreeze(&padst, sizeof(padst));