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