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