1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7// Dreamer Nom wrote:
8// Large thanks to John Weidman for all his initial research
9// Thanks to Seph3 for his modem notes
10
11
12#include "snes9x.h"
13#include "memmap.h"
14#include "display.h"
15#include <math.h>
16
17//#define BSX_DEBUG
18
19#define BIOS_SIZE 0x100000
20#define FLASH_SIZE 0x100000
21#define PSRAM_SIZE 0x80000
22
23#define Map Memory.Map
24#define BlockIsRAM Memory.BlockIsRAM
25#define BlockIsROM Memory.BlockIsROM
26#define RAM Memory.RAM
27#define SRAM Memory.SRAM
28#define PSRAM Memory.BSRAM
29#define BIOSROM Memory.BIOSROM
30#define MAP_BSX Memory.MAP_BSX
31#define MAP_CPU Memory.MAP_CPU
32#define MAP_PPU Memory.MAP_PPU
33#define MAP_NONE Memory.MAP_NONE
34
35#define BSXPPUBASE 0x2180
36
37struct SBSX_RTC
38{
39 int year;
40 int month;
41 int dayweek;
42 int day;
43 int hours;
44 int minutes;
45 int seconds;
46 int ticks;
47};
48
49static struct SBSX_RTC BSX_RTC;
50
51// flash card vendor information
52static const uint8 flashcard[20] =
53{
54 0x4D, 0x00, 0x50, 0x00, // vendor id
55 0x00, 0x00, // ?
56 0x1A, 0x00, // 2MB Flash (1MB = 0x2A)
57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
59};
60
61#if 0
62static const uint8 init2192[32] = // FIXME
63{
64 00, 00, 00, 00, 00, // unknown
65 01, 01, 00, 00, 00,
66 00, // seconds (?)
67 00, // minutes
68 00, // hours
69 10, 10, 10, 10, 10, // unknown
70 10, 10, 10, 10, 10, // dummy
71 00, 00, 00, 00, 00, 00, 00, 00, 00
72};
73#endif
74
75static bool8 FlashMode;
76static uint32 FlashSize;
77static uint8 *MapROM, *FlashROM;
78
79static void BSX_Map_SNES (void);
80static void BSX_Map_LoROM (void);
81static void BSX_Map_HiROM (void);
82static void BSX_Map_MMC (void);
83static void BSX_Map_FlashIO (void);
84static void BSX_Map_SRAM (void);
85static void BSX_Map_PSRAM (void);
86static void BSX_Map_BIOS (void);
87static void BSX_Map_RAM (void);
88static void BSX_Map (void);
89static bool8 BSX_LoadBIOS (void);
90static void map_psram_mirror_sub (uint32);
91static int is_bsx (unsigned char *);
92
93
94static void BSX_Map_SNES (void)
95{
96 // These maps will be partially overwritten
97
98 int c;
99
100 // Banks 00->3F and 80->BF
101 for (c = 0; c < 0x400; c += 16)
102 {
103 Map[c + 0] = Map[c + 0x800] = RAM;
104 Map[c + 1] = Map[c + 0x801] = RAM;
105 BlockIsRAM[c + 0] = BlockIsRAM[c + 0x800] = TRUE;
106 BlockIsRAM[c + 1] = BlockIsRAM[c + 0x801] = TRUE;
107
108 Map[c + 2] = Map[c + 0x802] = (uint8 *) MAP_PPU;
109 Map[c + 3] = Map[c + 0x803] = (uint8 *) MAP_PPU;
110 Map[c + 4] = Map[c + 0x804] = (uint8 *) MAP_CPU;
111 Map[c + 5] = Map[c + 0x805] = (uint8 *) MAP_CPU;
112 Map[c + 6] = Map[c + 0x806] = (uint8 *) MAP_NONE;
113 Map[c + 7] = Map[c + 0x807] = (uint8 *) MAP_NONE;
114 }
115}
116
117static void BSX_Map_LoROM (void)
118{
119 // These maps will be partially overwritten
120
121 int i, c;
122
123 // Banks 00->3F and 80->BF
124 for (c = 0; c < 0x400; c += 16)
125 {
126 for (i = c + 8; i < c + 16; i++)
127 {
128 Map[i] = Map[i + 0x800] = &MapROM[(c << 11) % FlashSize] - 0x8000;
129 BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable;
130 BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable;
131 }
132 }
133
134 // Banks 40->7F and C0->FF
135 for (c = 0; c < 0x400; c += 16)
136 {
137 for (i = c; i < c + 8; i++)
138 Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 11) % FlashSize];
139
140 for (i = c + 8; i < c + 16; i++)
141 Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 11) % FlashSize] - 0x8000;
142
143 for (i = c; i < c + 16; i++)
144 {
145 BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = BSX.write_enable;
146 BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = !BSX.write_enable;
147 }
148 }
149}
150
151static void BSX_Map_HiROM (void)
152{
153 // These maps will be partially overwritten
154
155 int i, c;
156
157 // Banks 00->3F and 80->BF
158 for (c = 0; c < 0x400; c += 16)
159 {
160 for (i = c + 8; i < c + 16; i++)
161 {
162 Map[i] = Map[i + 0x800] = &MapROM[(c << 12) % FlashSize];
163 BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable;
164 BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable;
165 }
166 }
167
168 // Banks 40->7F and C0->FF
169 for (c = 0; c < 0x400; c += 16)
170 {
171 for (i = c; i < c + 16; i++)
172 {
173 Map[i + 0x400] = Map[i + 0xC00] = &MapROM[(c << 12) % FlashSize];
174 BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = BSX.write_enable;
175 BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = !BSX.write_enable;
176 }
177 }
178}
179
180static void BSX_Map_MMC (void)
181{
182 int c;
183
184 // Banks 01->0E:5000-5FFF
185 for (c = 0x010; c < 0x0F0; c += 16)
186 {
187 Map[c + 5] = (uint8 *) MAP_BSX;
188 BlockIsRAM[c + 5] = BlockIsROM[c + 5] = FALSE;
189 }
190}
191
192static void BSX_Map_FlashIO (void)
193{
194 int i, c;
195
196 if (BSX.prevMMC[0x0C])
197 {
198 // Banks 00->3F and 80->BF
199 for (c = 0; c < 0x400; c += 16)
200 {
201 for (i = c + 8; i < c + 16; i++)
202 {
203 Map[i] = Map[i + 0x800] = (uint8 *)MAP_BSX;
204 BlockIsRAM[i] = BlockIsRAM[i + 0x800] = TRUE;
205 BlockIsROM[i] = BlockIsROM[i + 0x800] = FALSE;
206 }
207 }
208
209 // Banks 40->7F and C0->FF
210 for (c = 0; c < 0x400; c += 16)
211 {
212 for (i = c; i < c + 16; i++)
213 {
214 Map[i + 0x400] = Map[i + 0xC00] = (uint8 *)MAP_BSX;
215 BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = TRUE;
216 BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = FALSE;
217 }
218 }
219 }
220}
221
222static void BSX_Map_SRAM (void)
223{
224 int c;
225
226 // Banks 10->17:5000-5FFF
227 for (c = 0x100; c < 0x180; c += 16)
228 {
229 Map[c + 5] = (uint8 *) SRAM + ((c & 0x70) << 8) - 0x5000;
230 BlockIsRAM[c + 5] = TRUE;
231 BlockIsROM[c + 5] = FALSE;
232 }
233}
234
235static void map_psram_mirror_sub (uint32 bank)
236{
237 int i, c;
238
239 bank <<= 4;
240
241 if (BSX.prevMMC[0x02])
242 {
243 //HiROM
244 for (c = 0; c < 0x80; c += 16)
245 {
246 if ((bank & 0x7F0) >= 0x400)
247 {
248 for (i = c; i < c + 16; i++)
249 {
250 Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE];
251 BlockIsRAM[i + bank] = TRUE;
252 BlockIsROM[i + bank] = FALSE;
253 }
254 }
255 else
256 {
257 for (i = c + 8; i < c + 16; i++)
258 {
259 Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE];
260 BlockIsRAM[i + bank] = TRUE;
261 BlockIsROM[i + bank] = FALSE;
262 }
263 }
264 }
265 }
266 else
267 {
268 //LoROM
269 for (c = 0; c < 0x100; c += 16)
270 {
271 if ((bank & 0x7F0) >= 0x400)
272 {
273 for (i = c; i < c + 8; i++)
274 {
275 Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE];
276 BlockIsRAM[i + bank] = TRUE;
277 BlockIsROM[i + bank] = FALSE;
278 }
279 }
280
281 for (i = c + 8; i < c + 16; i++)
282 {
283 Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE] - 0x8000;
284 BlockIsRAM[i + bank] = TRUE;
285 BlockIsROM[i + bank] = FALSE;
286 }
287 }
288 }
289}
290
291static void BSX_Map_PSRAM(void)
292{
293 int c;
294
295 if (!BSX.prevMMC[0x02])
296 {
297 //LoROM Mode
298 if (!BSX.prevMMC[0x05] && !BSX.prevMMC[0x06])
299 {
300 //Map PSRAM to 00-0F/80-8F
301 if (BSX.prevMMC[0x03])
302 map_psram_mirror_sub(0x00);
303
304 if (BSX.prevMMC[0x04])
305 map_psram_mirror_sub(0x80);
306 }
307 else if (BSX.prevMMC[0x05] && !BSX.prevMMC[0x06])
308 {
309 //Map PSRAM to 20-2F/A0-AF
310 if (BSX.prevMMC[0x03])
311 map_psram_mirror_sub(0x20);
312
313 if (BSX.prevMMC[0x04])
314 map_psram_mirror_sub(0xA0);
315 }
316 else if (!BSX.prevMMC[0x05] && BSX.prevMMC[0x06])
317 {
318 //Map PSRAM to 40-4F/C0-CF
319 if (BSX.prevMMC[0x03])
320 map_psram_mirror_sub(0x40);
321
322 if (BSX.prevMMC[0x04])
323 map_psram_mirror_sub(0xC0);
324 }
325 else
326 {
327 //Map PSRAM to 60-6F/E0-EF
328 if (BSX.prevMMC[0x03])
329 map_psram_mirror_sub(0x60);
330
331 if (BSX.prevMMC[0x04])
332 map_psram_mirror_sub(0xE0);
333 }
334
335 //Map PSRAM to 70-7D/F0-FF
336 if (BSX.prevMMC[0x03])
337 map_psram_mirror_sub(0x70);
338
339 if (BSX.prevMMC[0x04])
340 map_psram_mirror_sub(0xF0);
341 }
342 else
343 {
344 //HiROM Mode
345 if (!BSX.prevMMC[0x05] && !BSX.prevMMC[0x06])
346 {
347 //Map PSRAM to 00-07/40-47 / 80-87/C0-C7
348 if (BSX.prevMMC[0x03])
349 {
350 map_psram_mirror_sub(0x00);
351 map_psram_mirror_sub(0x40);
352 }
353
354 if (BSX.prevMMC[0x04])
355 {
356 map_psram_mirror_sub(0x80);
357 map_psram_mirror_sub(0xC0);
358 }
359 }
360 else if (BSX.prevMMC[0x05] && !BSX.prevMMC[0x06])
361 {
362 //Map PSRAM to 10-17/50-57 / 90-97-D0-D7
363 if (BSX.prevMMC[0x03])
364 {
365 map_psram_mirror_sub(0x10);
366 map_psram_mirror_sub(0x50);
367 }
368
369 if (BSX.prevMMC[0x04])
370 {
371 map_psram_mirror_sub(0x90);
372 map_psram_mirror_sub(0xD0);
373 }
374 }
375 else if (!BSX.prevMMC[0x05] && BSX.prevMMC[0x06])
376 {
377 //Map PSRAM to 20-27/60-67 / A0-A7/E0-E7
378 if (BSX.prevMMC[0x03])
379 {
380 map_psram_mirror_sub(0x20);
381 map_psram_mirror_sub(0x60);
382 }
383
384 if (BSX.prevMMC[0x04])
385 {
386 map_psram_mirror_sub(0xA0);
387 map_psram_mirror_sub(0xE0);
388 }
389 }
390 else
391 {
392 //Map PSRAM to 30-37/70-77 / B0-B7/F0-F7
393 if (BSX.prevMMC[0x03])
394 {
395 map_psram_mirror_sub(0x30);
396 map_psram_mirror_sub(0x70);
397 }
398
399 if (BSX.prevMMC[0x04])
400 {
401 map_psram_mirror_sub(0xB0);
402 map_psram_mirror_sub(0xF0);
403 }
404 }
405
406 if (BSX.prevMMC[0x03])
407 {
408 //Map PSRAM to 20->3F:6000-7FFF
409 for (c = 0x200; c < 0x400; c += 16)
410 {
411 Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
412 Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
413 BlockIsRAM[c + 6] = TRUE;
414 BlockIsRAM[c + 7] = TRUE;
415 BlockIsROM[c + 6] = FALSE;
416 BlockIsROM[c + 7] = FALSE;
417 }
418 }
419
420 if (BSX.prevMMC[0x04])
421 {
422 //Map PSRAM to A0->BF:6000-7FFF
423 for (c = 0xA00; c < 0xC00; c += 16)
424 {
425 Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
426 Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE];
427 BlockIsRAM[c + 6] = TRUE;
428 BlockIsRAM[c + 7] = TRUE;
429 BlockIsROM[c + 6] = FALSE;
430 BlockIsROM[c + 7] = FALSE;
431 }
432 }
433 }
434}
435
436static void BSX_Map_BIOS (void)
437{
438 int i,c;
439
440 // Banks 00->1F:8000-FFFF
441 if (BSX.prevMMC[0x07])
442 {
443 for (c = 0; c < 0x200; c += 16)
444 {
445 for (i = c + 8; i < c + 16; i++)
446 {
447 Map[i] = &BIOSROM[(c << 11) % BIOS_SIZE] - 0x8000;
448 BlockIsRAM[i] = FALSE;
449 BlockIsROM[i] = TRUE;
450 }
451 }
452 }
453
454 // Banks 80->9F:8000-FFFF
455 if (BSX.prevMMC[0x08])
456 {
457 for (c = 0; c < 0x200; c += 16)
458 {
459 for (i = c + 8; i < c + 16; i++)
460 {
461 Map[i + 0x800] = &BIOSROM[(c << 11) % BIOS_SIZE] - 0x8000;
462 BlockIsRAM[i + 0x800] = FALSE;
463 BlockIsROM[i + 0x800] = TRUE;
464 }
465 }
466 }
467}
468
469static void BSX_Map_RAM (void)
470{
471 int c;
472
473 // Banks 7E->7F
474 for (c = 0; c < 16; c++)
475 {
476 Map[c + 0x7E0] = RAM;
477 Map[c + 0x7F0] = RAM + 0x10000;
478 BlockIsRAM[c + 0x7E0] = TRUE;
479 BlockIsRAM[c + 0x7F0] = TRUE;
480 BlockIsROM[c + 0x7E0] = FALSE;
481 BlockIsROM[c + 0x7F0] = FALSE;
482 }
483}
484
485static void BSX_Map (void)
486{
487#ifdef BSX_DEBUG
488 printf("BS: Remapping\n");
489 for (int i = 0; i < 32; i++)
490 printf("BS: MMC %02X: %d\n", i, BSX.MMC[i]);
491#endif
492
493 memcpy(BSX.prevMMC, BSX.MMC, sizeof(BSX.MMC));
494
495 MapROM = FlashROM;
496 FlashSize = FLASH_SIZE;
497
498 if (BSX.prevMMC[0x02])
499 BSX_Map_HiROM();
500 else
501 BSX_Map_LoROM();
502
503 BSX_Map_FlashIO();
504 BSX_Map_PSRAM();
505
506 BSX_Map_SNES();
507 BSX_Map_SRAM();
508 BSX_Map_RAM();
509
510 BSX_Map_BIOS();
511 BSX_Map_MMC();
512
513 // Monitor new register changes
514 BSX.dirty = FALSE;
515 BSX.dirty2 = FALSE;
516
517 Memory.map_WriteProtectROM();
518}
519
520static uint8 BSX_Get_Bypass_FlashIO (uint32 offset)
521{
522 //For games other than BS-X
523 FlashROM = Memory.ROM + Multi.cartOffsetB;
524
525 if (BSX.prevMMC[0x02])
526 return (FlashROM[offset & 0x0FFFFF]);
527 else
528 return (FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)]);
529}
530
531static void BSX_Set_Bypass_FlashIO (uint32 offset, uint8 byte)
532{
533 //For games other than BS-X
534 FlashROM = Memory.ROM + Multi.cartOffsetB;
535
536 if (BSX.prevMMC[0x02])
537 FlashROM[offset & 0x0FFFFF] = FlashROM[offset & 0x0FFFFF] & byte;
538 else
539 FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] = FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] & byte;
540}
541
542uint8 S9xGetBSX (uint32 address)
543{
544 uint8 bank = (address >> 16) & 0xFF;
545 uint16 offset = address & 0xFFFF;
546 uint8 t = 0;
547
548 // MMC
549 if ((bank >= 0x01 && bank <= 0x0E) && ((address & 0xF000) == 0x5000))
550 return (BSX.MMC[bank]);
551
552 // Flash Mapping
553
554 // default: read-through mode
555 t = BSX_Get_Bypass_FlashIO(address);
556
557 // note: may be more registers, purposes unknown
558 switch (offset)
559 {
560 case 0x0002:
561 case 0x8002:
562 if (BSX.flash_bsr)
563 t = 0xC0; // Page Status Register
564 break;
565
566 case 0x0004:
567 case 0x8004:
568 if (BSX.flash_gsr)
569 t = 0x82; // Global Status Register
570 break;
571
572 case 0x5555:
573 if (BSX.flash_enable)
574 t = 0x80; // ???
575 break;
576
577 case 0xFF00:
578 case 0xFF02:
579 case 0xFF04:
580 case 0xFF06:
581 case 0xFF08:
582 case 0xFF0A:
583 case 0xFF0C:
584 case 0xFF0E:
585 case 0xFF10:
586 case 0xFF12:
587 // return flash vendor information
588 if (BSX.read_enable)
589 t = flashcard[offset - 0xFF00];
590 break;
591 }
592
593 if (BSX.flash_csr)
594 {
595 t = 0x80; // Compatible Status Register
596 BSX.flash_csr = false;
597 }
598
599 return (t);
600}
601
602void S9xSetBSX (uint8 byte, uint32 address)
603{
604 uint8 bank = (address >> 16) & 0xFF;
605
606 // MMC
607 if ((bank >= 0x01 && bank <= 0x0E) && ((address & 0xF000) == 0x5000))
608 {
609 //Avoid updating the memory map when it is not needed
610 if (bank == 0x0E && BSX.dirty)
611 {
612 BSX_Map();
613 BSX.dirty = FALSE;
614 }
615 else if (bank != 0x0E && BSX.MMC[bank] != byte)
616 {
617 BSX.dirty = TRUE;
618 }
619
620 BSX.MMC[bank] = byte;
621 }
622
623 // Flash IO
624
625 // Write to Flash
626 if (BSX.write_enable)
627 {
628 BSX_Set_Bypass_FlashIO(address, byte);
629 BSX.write_enable = false;
630 return;
631 }
632
633 // Flash Command Handling
634
635 //Memory Pack Type 1 & 3 & 4
636 BSX.flash_command <<= 8;
637 BSX.flash_command |= byte;
638
639 switch (BSX.flash_command & 0xFF)
640 {
641 case 0x00:
642 case 0xFF:
643 //Reset to normal
644 BSX.flash_enable = false;
645 BSX.flash_bsr = false;
646 BSX.flash_csr = false;
647 BSX.flash_gsr = false;
648 BSX.read_enable = false;
649 BSX.write_enable = false;
650 BSX.flash_cmd_done = true;
651 break;
652
653 case 0x10:
654 case 0x40:
655 //Write Byte
656 BSX.flash_enable = false;
657 BSX.flash_bsr = false;
658 BSX.flash_csr = true;
659 BSX.flash_gsr = false;
660 BSX.read_enable = false;
661 BSX.write_enable = true;
662 BSX.flash_cmd_done = true;
663 break;
664
665 case 0x50:
666 //Clear Status Register
667 BSX.flash_enable = false;
668 BSX.flash_bsr = false;
669 BSX.flash_csr = false;
670 BSX.flash_gsr = false;
671 BSX.flash_cmd_done = true;
672 break;
673
674 case 0x70:
675 //Read CSR
676 BSX.flash_enable = false;
677 BSX.flash_bsr = false;
678 BSX.flash_csr = true;
679 BSX.flash_gsr = false;
680 BSX.read_enable = false;
681 BSX.write_enable = false;
682 BSX.flash_cmd_done = true;
683 break;
684
685 case 0x71:
686 //Read Extended Status Registers (Page and Global)
687 BSX.flash_enable = false;
688 BSX.flash_bsr = true;
689 BSX.flash_csr = false;
690 BSX.flash_gsr = true;
691 BSX.read_enable = false;
692 BSX.write_enable = false;
693 BSX.flash_cmd_done = true;
694 break;
695
696 case 0x75:
697 //Show Page Buffer / Vendor Info
698 BSX.flash_csr = false;
699 BSX.read_enable = true;
700 BSX.flash_cmd_done = true;
701 break;
702
703 case 0xD0:
704 //DO COMMAND
705 switch (BSX.flash_command & 0xFFFF)
706 {
707 case 0x20D0: //Block Erase
708 uint32 x;
709 for (x = 0; x < 0x10000; x++) {
710 //BSX_Set_Bypass_FlashIO(((address & 0xFF0000) + x), 0xFF);
711 if (BSX.MMC[0x02])
712 FlashROM[(address & 0x0F0000) + x] = 0xFF;
713 else
714 FlashROM[((address & 0x1E0000) >> 1) + x] = 0xFF;
715 }
716 break;
717
718 case 0xA7D0: //Chip Erase (ONLY IN TYPE 1 AND 4)
719 if ((flashcard[6] & 0xF0) == 0x10 || (flashcard[6] & 0xF0) == 0x40)
720 {
721 uint32 x;
722 for (x = 0; x < FLASH_SIZE; x++) {
723 //BSX_Set_Bypass_FlashIO(x, 0xFF);
724 FlashROM[x] = 0xFF;
725 }
726 }
727 break;
728
729 case 0x38D0: //Flashcart Reset
730 break;
731 }
732 break;
733 }
734}
735
736void S9xBSXSetStream1 (uint8 count)
737{
738 if (BSX.sat_stream1.is_open())
739 BSX.sat_stream1.close(); //If Stream already opened for one file: Close it.
740
741 char path[PATH_MAX + 1], name[PATH_MAX + 1];
742
743 strcpy(path, S9xGetDirectory(SAT_DIR));
744 strcat(path, SLASH_STR);
745
746 snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x2188 - BSXPPUBASE] | (BSX.PPU[0x2189 - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin
747 strcat(path, name);
748
749 BSX.sat_stream1.clear();
750 BSX.sat_stream1.open(path, std::ios::in | std::ios::binary);
751 if (BSX.sat_stream1.good())
752 {
753 BSX.sat_stream1.seekg(0, BSX.sat_stream1.end);
754 long str1size = BSX.sat_stream1.tellg();
755 BSX.sat_stream1.seekg(0, BSX.sat_stream1.beg);
756 float QueueSize = str1size / 22.;
757 BSX.sat_stream1_queue = (uint16)(ceil(QueueSize));
758 BSX.PPU[0x218D - BSXPPUBASE] = 0;
759 BSX.sat_stream1_first = TRUE;
760 BSX.sat_stream1_loaded = TRUE;
761 }
762 else
763 {
764 BSX.sat_stream1_loaded = FALSE;
765 }
766}
767
768void S9xBSXSetStream2 (uint8 count)
769{
770 if (BSX.sat_stream2.is_open())
771 BSX.sat_stream2.close(); //If Stream already opened for one file: Close it.
772
773 char path[PATH_MAX + 1], name[PATH_MAX + 1];
774
775 strcpy(path, S9xGetDirectory(SAT_DIR));
776 strcat(path, SLASH_STR);
777
778 snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x218E - BSXPPUBASE] | (BSX.PPU[0x218F - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin
779 strcat(path, name);
780
781 BSX.sat_stream2.clear();
782 BSX.sat_stream2.open(path, std::ios::in | std::ios::binary);
783 if (BSX.sat_stream2.good())
784 {
785 BSX.sat_stream2.seekg(0, BSX.sat_stream2.end);
786 long str2size = BSX.sat_stream2.tellg();
787 BSX.sat_stream2.seekg(0, BSX.sat_stream2.beg);
788 float QueueSize = str2size / 22.;
789 BSX.sat_stream2_queue = (uint16)(ceil(QueueSize));
790 BSX.PPU[0x2193 - BSXPPUBASE] = 0;
791 BSX.sat_stream2_first = TRUE;
792 BSX.sat_stream2_loaded = TRUE;
793 }
794 else
795 {
796 BSX.sat_stream2_loaded = FALSE;
797 }
798}
799
800uint8 S9xBSXGetRTC (void)
801{
802 //Get Time
803 time_t t;
804 struct tm *tmr;
805
806 time(&t);
807 tmr = localtime(&t);
808
809 BSX.test2192[0] = 0x00;
810 BSX.test2192[1] = 0x00;
811 BSX.test2192[2] = 0x00;
812 BSX.test2192[3] = 0x00;
813 BSX.test2192[4] = 0x10;
814 BSX.test2192[5] = 0x01;
815 BSX.test2192[6] = 0x01;
816 BSX.test2192[7] = 0x00;
817 BSX.test2192[8] = 0x00;
818 BSX.test2192[9] = 0x00;
819 BSX.test2192[10] = BSX_RTC.seconds = tmr->tm_sec;
820 BSX.test2192[11] = BSX_RTC.minutes = tmr->tm_min;
821 BSX.test2192[12] = BSX_RTC.hours = tmr->tm_hour;
822 BSX.test2192[13] = BSX_RTC.dayweek = (tmr->tm_wday) + 1;
823 BSX.test2192[14] = BSX_RTC.day = tmr->tm_mday;
824 BSX.test2192[15] = BSX_RTC.month = (tmr->tm_mon) + 1;
825 BSX_RTC.year = tmr->tm_year + 1900;
826 BSX.test2192[16] = (BSX_RTC.year) & 0xFF;
827 BSX.test2192[17] = (BSX_RTC.year) >> 8;
828
829 t = BSX.test2192[BSX.out_index++];
830
831 if (BSX.out_index > 22)
832 BSX.out_index = 0;
833
834 return t;
835}
836
837uint8 S9xGetBSXPPU (uint16 address)
838{
839 uint8 t;
840
841 // known read registers
842 switch (address)
843 {
844 //Stream 1
845 // Logical Channel 1 + Data Structure (R/W)
846 case 0x2188:
847 t = BSX.PPU[0x2188 - BSXPPUBASE];
848 break;
849
850 // Logical Channel 2 (R/W) [6bit]
851 case 0x2189:
852 t = BSX.PPU[0x2189 - BSXPPUBASE];
853 break;
854
855 // Prefix Count (R)
856 case 0x218A:
857 if (!BSX.sat_pf_latch1_enable || !BSX.sat_dt_latch1_enable)
858 {
859 t = 0;
860 break;
861 }
862
863 if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0)
864 {
865 t = 1;
866 break;
867 }
868
869 if (BSX.sat_stream1_queue <= 0)
870 {
871 BSX.sat_stream1_count++;
872 S9xBSXSetStream1(BSX.sat_stream1_count - 1);
873 }
874
875 if (!BSX.sat_stream1_loaded && (BSX.sat_stream1_count - 1) > 0)
876 {
877 BSX.sat_stream1_count = 1;
878 S9xBSXSetStream1(BSX.sat_stream1_count - 1);
879 }
880
881 if (BSX.sat_stream1_loaded)
882 {
883 //Lock at 0x7F for bigger packets
884 if (BSX.sat_stream1_queue >= 128)
885 BSX.PPU[0x218A - BSXPPUBASE] = 0x7F;
886 else
887 BSX.PPU[0x218A - BSXPPUBASE] = BSX.sat_stream1_queue;
888 t = BSX.PPU[0x218A - BSXPPUBASE];
889 }
890 else
891 t = 0;
892 break;
893
894 // Prefix Latch (R/W)
895 case 0x218B:
896 if (BSX.sat_pf_latch1_enable)
897 {
898 if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0)
899 {
900 BSX.PPU[0x218B - BSXPPUBASE] = 0x90;
901 }
902
903 if (BSX.sat_stream1_loaded)
904 {
905 uint8 temp = 0;
906 if (BSX.sat_stream1_first)
907 {
908 // First packet
909 temp |= 0x10;
910 BSX.sat_stream1_first = FALSE;
911 }
912
913 BSX.sat_stream1_queue--;
914
915 if (BSX.sat_stream1_queue == 0)
916 {
917 //Last packet
918 temp |= 0x80;
919 }
920
921 BSX.PPU[0x218B - BSXPPUBASE] = temp;
922 }
923
924 BSX.PPU[0x218D - BSXPPUBASE] |= BSX.PPU[0x218B - BSXPPUBASE];
925 t = BSX.PPU[0x218B - BSXPPUBASE];
926 }
927 else
928 {
929 t = 0;
930 }
931 break;
932
933 // Data Latch (R/W)
934 case 0x218C:
935 if (BSX.sat_dt_latch1_enable)
936 {
937 if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0)
938 {
939 BSX.PPU[0x218C - BSXPPUBASE] = S9xBSXGetRTC();
940 }
941 else if (BSX.sat_stream1_loaded)
942 {
943 if (BSX.sat_stream1.eof())
944 BSX.PPU[0x218C - BSXPPUBASE] = 0xFF;
945 else
946 BSX.PPU[0x218C - BSXPPUBASE] = BSX.sat_stream1.get();
947 }
948 t = BSX.PPU[0x218C - BSXPPUBASE];
949 }
950 else
951 {
952 t = 0;
953 }
954 break;
955
956 // OR gate (R)
957 case 0x218D:
958 t = BSX.PPU[0x218D - BSXPPUBASE];
959 BSX.PPU[0x218D - BSXPPUBASE] = 0;
960 break;
961
962 //Stream 2
963 // Logical Channel 1 + Data Structure (R/W)
964 case 0x218E:
965 t = BSX.PPU[0x218E - BSXPPUBASE];
966 break;
967
968 // Logical Channel 2 (R/W) [6bit]
969 case 0x218F:
970 t = BSX.PPU[0x218F - BSXPPUBASE];
971 break;
972
973 // Prefix Count (R)
974 case 0x2190:
975 if (!BSX.sat_pf_latch2_enable || !BSX.sat_dt_latch2_enable)
976 {
977 t = 0;
978 break;
979 }
980
981 if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0)
982 {
983 t = 1;
984 break;
985 }
986
987 if (BSX.sat_stream2_queue <= 0)
988 {
989 BSX.sat_stream2_count++;
990 S9xBSXSetStream2(BSX.sat_stream2_count - 1);
991 }
992
993 if (!BSX.sat_stream2_loaded && (BSX.sat_stream2_count - 1) > 0)
994 {
995 BSX.sat_stream2_count = 1;
996 S9xBSXSetStream2(BSX.sat_stream2_count - 1);
997 }
998
999 if (BSX.sat_stream2_loaded)
1000 {
1001 if (BSX.sat_stream2_queue >= 128)
1002 BSX.PPU[0x2190 - BSXPPUBASE] = 0x7F;
1003 else
1004 BSX.PPU[0x2190 - BSXPPUBASE] = BSX.sat_stream2_queue;
1005 t = BSX.PPU[0x2190 - BSXPPUBASE];
1006 }
1007 else
1008 t = 0;
1009 break;
1010
1011 // Prefix Latch (R/W)
1012 case 0x2191:
1013 if (BSX.sat_pf_latch2_enable)
1014 {
1015 if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0)
1016 {
1017 BSX.PPU[0x2191 - BSXPPUBASE] = 0x90;
1018 }
1019
1020 if (BSX.sat_stream2_loaded)
1021 {
1022 uint8 temp = 0;
1023 if (BSX.sat_stream2_first)
1024 {
1025 // First packet
1026 temp |= 0x10;
1027 BSX.sat_stream2_first = FALSE;
1028 }
1029
1030 BSX.sat_stream2_queue--;
1031
1032 if (BSX.sat_stream2_queue == 0)
1033 {
1034 //Last packet
1035 temp |= 0x80;
1036 }
1037
1038 BSX.PPU[0x2191 - BSXPPUBASE] = temp;
1039 }
1040
1041 BSX.PPU[0x2193 - BSXPPUBASE] |= BSX.PPU[0x2191 - BSXPPUBASE];
1042 t = BSX.PPU[0x2191 - BSXPPUBASE];
1043 }
1044 else
1045 {
1046 t = 0;
1047 }
1048 break;
1049
1050 // Data Latch (R/W)
1051 case 0x2192:
1052 if (BSX.sat_dt_latch2_enable)
1053 {
1054 if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0)
1055 {
1056 BSX.PPU[0x2192 - BSXPPUBASE] = S9xBSXGetRTC();
1057 }
1058 else if (BSX.sat_stream2_loaded)
1059 {
1060 if (BSX.sat_stream2.eof())
1061 BSX.PPU[0x2192 - BSXPPUBASE] = 0xFF;
1062 else
1063 BSX.PPU[0x2192 - BSXPPUBASE] = BSX.sat_stream2.get();
1064 }
1065 t = BSX.PPU[0x2192 - BSXPPUBASE];
1066 }
1067 else
1068 {
1069 t = 0;
1070 }
1071 break;
1072
1073 // OR gate (R)
1074 case 0x2193:
1075 t = BSX.PPU[0x2193 - BSXPPUBASE];
1076 BSX.PPU[0x2193 - BSXPPUBASE] = 0;
1077 break;
1078
1079 //Other
1080 // Satellaview LED / Stream Enable (R/W) [4bit]
1081 case 0x2194:
1082 t = BSX.PPU[0x2194 - BSXPPUBASE];
1083 break;
1084
1085 // Unknown
1086 case 0x2195:
1087 t = BSX.PPU[0x2195 - BSXPPUBASE];
1088 break;
1089
1090 // Satellaview Status (R)
1091 case 0x2196:
1092 t = BSX.PPU[0x2196 - BSXPPUBASE];
1093 break;
1094
1095 // Soundlink Settings (R/W)
1096 case 0x2197:
1097 t = BSX.PPU[0x2197 - BSXPPUBASE];
1098 break;
1099
1100 // Serial I/O - Serial Number (R/W)
1101 case 0x2198:
1102 t = BSX.PPU[0x2198 - BSXPPUBASE];
1103 break;
1104
1105 // Serial I/O - Unknown (R/W)
1106 case 0x2199:
1107 t = BSX.PPU[0x2199 - BSXPPUBASE];
1108 break;
1109
1110 default:
1111 t = OpenBus;
1112 break;
1113 }
1114
1115 return (t);
1116}
1117
1118void S9xSetBSXPPU (uint8 byte, uint16 address)
1119{
1120 // known write registers
1121 switch (address)
1122 {
1123 //Stream 1
1124 // Logical Channel 1 + Data Structure (R/W)
1125 case 0x2188:
1126 if (BSX.PPU[0x2188 - BSXPPUBASE] == byte)
1127 {
1128 BSX.sat_stream1_count = 0;
1129 }
1130 BSX.PPU[0x2188 - BSXPPUBASE] = byte;
1131 break;
1132
1133 // Logical Channel 2 (R/W) [6bit]
1134 case 0x2189:
1135 if (BSX.PPU[0x2188 - BSXPPUBASE] == (byte & 0x3F))
1136 {
1137 BSX.sat_stream1_count = 0;
1138 }
1139 BSX.PPU[0x2189 - BSXPPUBASE] = byte & 0x3F;
1140 break;
1141
1142 // Prefix Latch (R/W)
1143 case 0x218B:
1144 BSX.sat_pf_latch1_enable = (byte != 0);
1145 break;
1146
1147 // Data Latch (R/W)
1148 case 0x218C:
1149 if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0)
1150 {
1151 BSX.out_index = 0;
1152 }
1153 BSX.sat_dt_latch1_enable = (byte != 0);
1154 break;
1155
1156 //Stream 2
1157 // Logical Channel 1 + Data Structure (R/W)
1158 case 0x218E:
1159 if (BSX.PPU[0x218E - BSXPPUBASE] == byte)
1160 {
1161 BSX.sat_stream2_count = 0;
1162 }
1163 BSX.PPU[0x218E - BSXPPUBASE] = byte;
1164 break;
1165
1166 // Logical Channel 2 (R/W) [6bit]
1167 case 0x218F:
1168 if (BSX.PPU[0x218F - BSXPPUBASE] == (byte & 0x3F))
1169 {
1170 BSX.sat_stream2_count = 0;
1171 }
1172 BSX.PPU[0x218F - BSXPPUBASE] = byte & 0x3F;
1173 break;
1174
1175 // Prefix Latch (R/W)
1176 case 0x2191:
1177 BSX.sat_pf_latch2_enable = (byte != 0);
1178 break;
1179
1180 // Data Latch (R/W)
1181 case 0x2192:
1182 if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0)
1183 {
1184 BSX.out_index = 0;
1185 }
1186 BSX.sat_dt_latch2_enable = (byte != 0);
1187 break;
1188
1189 //Other
1190 // Satellaview LED / Stream Enable (R/W) [4bit]
1191 case 0x2194:
1192 BSX.PPU[0x2194 - BSXPPUBASE] = byte & 0x0F;
1193 break;
1194
1195 // Soundlink Settings (R/W)
1196 case 0x2197:
1197 BSX.PPU[0x2197 - BSXPPUBASE] = byte;
1198 break;
1199 }
1200}
1201
1202uint8 * S9xGetBasePointerBSX (uint32 address)
1203{
1204 return (MapROM);
1205}
1206
1207static bool8 BSX_LoadBIOS (void)
1208{
1209 FILE *fp;
1210 char path[PATH_MAX + 1], name[PATH_MAX + 1];
1211 bool8 r = FALSE;
1212
1213 strcpy(path, S9xGetDirectory(BIOS_DIR));
1214 strcat(path, SLASH_STR);
1215 strcpy(name, path);
1216 strcat(name, "BS-X.bin");
1217
1218 fp = fopen(name, "rb");
1219 if (!fp)
1220 {
1221 strcpy(name, path);
1222 strcat(name, "BS-X.bios");
1223 fp = fopen(name, "rb");
1224 }
1225
1226 if (fp)
1227 {
1228 size_t size;
1229
1230 size = fread((void *) BIOSROM, 1, BIOS_SIZE, fp);
1231 fclose(fp);
1232 if (size == BIOS_SIZE)
1233 r = TRUE;
1234 }
1235
1236#ifdef BSX_DEBUG
1237 if (r)
1238 printf("BS: BIOS found.\n");
1239 else
1240 printf("BS: BIOS not found!\n");
1241#endif
1242
1243 return (r);
1244}
1245
1246static bool8 is_BSX_BIOS (const uint8 *data, uint32 size)
1247{
1248 if (size == BIOS_SIZE && strncmp((char *) (data + 0x7FC0), "Satellaview BS-X ", 21) == 0)
1249 return (TRUE);
1250 else
1251 return (FALSE);
1252}
1253
1254void S9xInitBSX (void)
1255{
1256 Settings.BS = FALSE;
1257
1258 if (is_BSX_BIOS(Memory.ROM,Memory.CalculatedSize))
1259 {
1260 // BS-X itself
1261
1262 Settings.BS = TRUE;
1263 Settings.BSXItself = TRUE;
1264
1265 Memory.LoROM = TRUE;
1266 Memory.HiROM = FALSE;
1267
1268 memmove(BIOSROM, Memory.ROM, BIOS_SIZE);
1269
1270 FlashMode = FALSE;
1271 FlashSize = FLASH_SIZE;
1272
1273 BSX.bootup = TRUE;
1274 }
1275 else
1276 {
1277 Settings.BSXItself = FALSE;
1278
1279 int r1, r2;
1280
1281 r1 = (is_bsx(Memory.ROM + 0x7FC0) == 1);
1282 r2 = (is_bsx(Memory.ROM + 0xFFC0) == 1);
1283 Settings.BS = (r1 | r2) ? TRUE : FALSE;
1284
1285 if (Settings.BS)
1286 {
1287 // BS games
1288
1289 Memory.LoROM = r1 ? TRUE : FALSE;
1290 Memory.HiROM = r2 ? TRUE : FALSE;
1291
1292 uint8 *header = r1 ? Memory.ROM + 0x7FC0 : Memory.ROM + 0xFFC0;
1293
1294 FlashMode = (header[0x18] & 0xEF) == 0x20 ? FALSE : TRUE;
1295 FlashSize = FLASH_SIZE;
1296
1297 // Fix Block Allocation Flags
1298 // (for games that don't have it setup properly,
1299 // for exemple when taken seperately from the upper memory of the Memory Pack,
1300 // else the game will error out on BS-X)
1301 for (; (((header[0x10] & 1) == 0) && header[0x10] != 0); (header[0x10] >>= 1));
1302
1303#ifdef BSX_DEBUG
1304 for (int i = 0; i <= 0x1F; i++)
1305 printf("BS: ROM Header %02X: %02X\n", i, header[i]);
1306 printf("BS: FlashMode: %d, FlashSize: %x\n", FlashMode, FlashSize);
1307#endif
1308
1309 BSX.bootup = Settings.BSXBootup;
1310
1311 if (!BSX_LoadBIOS() && !is_BSX_BIOS(BIOSROM,BIOS_SIZE))
1312 {
1313 BSX.bootup = FALSE;
1314 memset(BIOSROM, 0, BIOS_SIZE);
1315 }
1316 }
1317 }
1318
1319 if (Settings.BS)
1320 {
1321 MapROM = NULL;
1322 FlashROM = Memory.ROM;
1323 /*
1324 time_t t;
1325 struct tm *tmr;
1326
1327 time(&t);
1328 tmr = localtime(&t);
1329
1330 BSX_RTC.ticks = 0;
1331 memcpy(BSX.test2192, init2192, sizeof(init2192));
1332 BSX.test2192[10] = BSX_RTC.seconds = tmr->tm_sec;
1333 BSX.test2192[11] = BSX_RTC.minutes = tmr->tm_min;
1334 BSX.test2192[12] = BSX_RTC.hours = tmr->tm_hour;
1335#ifdef BSX_DEBUG
1336 printf("BS: Current Time: %02d:%02d:%02d\n", BSX_RTC.hours, BSX_RTC.minutes, BSX_RTC.seconds);
1337#endif
1338 */
1339 SNESGameFixes.SRAMInitialValue = 0x00;
1340 }
1341}
1342
1343void S9xResetBSX (void)
1344{
1345 if (Settings.BSXItself)
1346 memset(Memory.ROM, 0, FLASH_SIZE);
1347
1348 memset(BSX.PPU, 0, sizeof(BSX.PPU));
1349 memset(BSX.MMC, 0, sizeof(BSX.MMC));
1350 memset(BSX.prevMMC, 0, sizeof(BSX.prevMMC));
1351
1352 BSX.dirty = FALSE;
1353 BSX.dirty2 = FALSE;
1354 BSX.flash_enable = FALSE;
1355 BSX.write_enable = FALSE;
1356 BSX.read_enable = FALSE;
1357 BSX.flash_command = 0;
1358 BSX.old_write = 0;
1359 BSX.new_write = 0;
1360
1361 BSX.out_index = 0;
1362 memset(BSX.output, 0, sizeof(BSX.output));
1363
1364 // starting from the bios
1365 BSX.MMC[0x02] = BSX.MMC[0x03] = BSX.MMC[0x05] = BSX.MMC[0x06] = 0x80;
1366 BSX.MMC[0x09] = BSX.MMC[0x0B] = 0x80;
1367
1368 BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80;
1369 BSX.MMC[0x0E] = 0x80;
1370
1371 // default register values
1372 BSX.PPU[0x2196 - BSXPPUBASE] = 0x10;
1373 BSX.PPU[0x2197 - BSXPPUBASE] = 0x80;
1374
1375 // stream reset
1376 BSX.sat_pf_latch1_enable = BSX.sat_dt_latch1_enable = FALSE;
1377 BSX.sat_pf_latch2_enable = BSX.sat_dt_latch2_enable = FALSE;
1378
1379 BSX.sat_stream1_loaded = BSX.sat_stream2_loaded = FALSE;
1380 BSX.sat_stream1_first = BSX.sat_stream2_first = FALSE;
1381 BSX.sat_stream1_count = BSX.sat_stream2_count = 0;
1382
1383 if (BSX.sat_stream1.is_open())
1384 BSX.sat_stream1.close();
1385
1386 if (BSX.sat_stream2.is_open())
1387 BSX.sat_stream2.close();
1388
1389 if (Settings.BS)
1390 BSX_Map();
1391}
1392
1393void S9xBSXPostLoadState (void)
1394{
1395 uint8 temp[16];
1396 bool8 pd1, pd2;
1397
1398 pd1 = BSX.dirty;
1399 pd2 = BSX.dirty2;
1400 memcpy(temp, BSX.MMC, sizeof(BSX.MMC));
1401
1402 memcpy(BSX.MMC, BSX.prevMMC, sizeof(BSX.MMC));
1403 BSX_Map();
1404
1405 memcpy(BSX.MMC, temp, sizeof(BSX.MMC));
1406 BSX.dirty = pd1;
1407 BSX.dirty2 = pd2;
1408}
1409
1410static bool valid_normal_bank (unsigned char bankbyte)
1411{
1412 switch (bankbyte)
1413 {
1414 case 32: case 33: case 48: case 49:
1415 return (true);
1416 break;
1417 }
1418
1419 return (false);
1420}
1421
1422static int is_bsx (unsigned char *p)
1423{
1424 if ((p[26] == 0x33 || p[26] == 0xFF) && (!p[21] || (p[21] & 131) == 128) && valid_normal_bank(p[24]))
1425 {
1426 unsigned char m = p[22];
1427
1428 if (!m && !p[23])
1429 return (2);
1430
1431 if ((m == 0xFF && p[23] == 0xFF) || (!(m & 0xF) && ((m >> 4) - 1 < 12)))
1432 return (1);
1433 }
1434
1435 return (0);
1436}
1437