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