diff --git a/source/snes9x/bsx.cpp b/source/snes9x/bsx.cpp index abee8a7..18dde0f 100644 --- a/source/snes9x/bsx.cpp +++ b/source/snes9x/bsx.cpp @@ -17,13 +17,20 @@ (c) Copyright 2002 - 2010 Brad Jorsch (anomie@users.sourceforge.net), Nach (n-a-c-h@users.sourceforge.net), - zones (kasumitokoduck@yahoo.com) + + (c) Copyright 2002 - 2011 zones (kasumitokoduck@yahoo.com) (c) Copyright 2006 - 2007 nitsuja - (c) Copyright 2009 - 2010 BearOso, + (c) Copyright 2009 - 2018 BearOso, OV2 + (c) Copyright 2017 qwertymodo + + (c) Copyright 2011 - 2017 Hans-Kristian Arntzen, + Daniel De Matteis + (Under no circumstances will commercial rights be given) + BS-X C emulator code (c) Copyright 2005 - 2006 Dreamer Nom, @@ -117,6 +124,9 @@ Sound emulator code used in 1.52+ (c) Copyright 2004 - 2007 Shay Green (gblargg@gmail.com) + S-SMP emulator code used in 1.54+ + (c) Copyright 2016 byuu + SH assembler code partly based on x86 assembler code (c) Copyright 2002 - 2004 Marcus Comstedt (marcus@mc.pp.se) @@ -130,7 +140,7 @@ (c) Copyright 2006 - 2007 Shay Green GTK+ GUI code - (c) Copyright 2004 - 2010 BearOso + (c) Copyright 2004 - 2018 BearOso Win32 GUI code (c) Copyright 2003 - 2006 blip, @@ -138,11 +148,16 @@ Matthew Kendora, Nach, nitsuja - (c) Copyright 2009 - 2010 OV2 + (c) Copyright 2009 - 2018 OV2 Mac OS GUI code (c) Copyright 1998 - 2001 John Stiles - (c) Copyright 2001 - 2010 zones + (c) Copyright 2001 - 2011 zones + + Libretro port + (c) Copyright 2011 - 2017 Hans-Kristian Arntzen, + Daniel De Matteis + (Under no circumstances will commercial rights be given) Specific ports contains the works of other authors. See headers in @@ -182,11 +197,12 @@ #include "snes9x.h" #include "memmap.h" #include "display.h" +#include //#define BSX_DEBUG #define BIOS_SIZE 0x100000 -#define FLASH_SIZE 0x200000 +#define FLASH_SIZE 0x100000 #define PSRAM_SIZE 0x80000 #define Map Memory.Map @@ -205,6 +221,10 @@ struct SBSX_RTC { + int year; + int month; + int dayweek; + int day; int hours; int minutes; int seconds; @@ -218,7 +238,7 @@ static const uint8 flashcard[20] = { 0x4D, 0x00, 0x50, 0x00, // vendor id 0x00, 0x00, // ? - 0x2B, 0x00, // 2MB Flash (1MB = 0x2A) + 0x1A, 0x00, // 2MB Flash (1MB = 0x2A) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -248,10 +268,7 @@ static void BSX_Map_SRAM (void); static void BSX_Map_PSRAM (void); static void BSX_Map_BIOS (void); static void BSX_Map_RAM (void); -static void BSX_Map_Dirty (void); static void BSX_Map (void); -static void BSX_Set_Bypass_FlashIO (uint16, uint8); -static uint8 BSX_Get_Bypass_FlashIO (uint16); static bool8 BSX_LoadBIOS (void); static void map_psram_mirror_sub (uint32); static int is_bsx (unsigned char *); @@ -357,16 +374,30 @@ static void BSX_Map_MMC (void) static void BSX_Map_FlashIO (void) { - int c; + int i, c; - if (BSX.MMC[0x0C] || BSX.MMC[0x0D]) + if (BSX.prevMMC[0x0C]) { - // Bank C0:0000, 2AAA, 5555, FF00-FF1F - for (c = 0; c < 16; c++) + // Banks 00->3F and 80->BF + for (c = 0; c < 0x400; c += 16) { - Map[c + 0xC00] = (uint8 *) MAP_BSX; - BlockIsRAM[c + 0xC00] = TRUE; - BlockIsROM[c + 0xC00] = FALSE; + for (i = c + 8; i < c + 16; i++) + { + Map[i] = Map[i + 0x800] = (uint8 *)MAP_BSX; + BlockIsRAM[i] = BlockIsRAM[i + 0x800] = TRUE; + BlockIsROM[i] = BlockIsROM[i + 0x800] = FALSE; + } + } + + // Banks 40->7F and C0->FF + for (c = 0; c < 0x400; c += 16) + { + for (i = c; i < c + 16; i++) + { + Map[i + 0x400] = Map[i + 0xC00] = (uint8 *)MAP_BSX; + BlockIsRAM[i + 0x400] = BlockIsRAM[i + 0xC00] = TRUE; + BlockIsROM[i + 0x400] = BlockIsROM[i + 0xC00] = FALSE; + } } } } @@ -390,30 +421,49 @@ static void map_psram_mirror_sub (uint32 bank) bank <<= 4; - if (BSX.MMC[0x02]) + if (BSX.prevMMC[0x02]) { - for (c = 0; c < 0x100; c += 16) + //HiROM + for (c = 0; c < 0x80; c += 16) { - for (i = c; i < c + 16; i++) + if ((bank & 0x7F0) >= 0x400) { - Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE]; - BlockIsRAM[i + bank] = TRUE; - BlockIsROM[i + bank] = FALSE; + for (i = c; i < c + 16; i++) + { + Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE]; + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } + } + else + { + for (i = c + 8; i < c + 16; i++) + { + Map[i + bank] = &PSRAM[(c << 12) % PSRAM_SIZE]; + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } } } } else { + //LoROM for (c = 0; c < 0x100; c += 16) { - for (i = c; i < c + 8; i++) - Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE]; + if ((bank & 0x7F0) >= 0x400) + { + for (i = c; i < c + 8; i++) + { + Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE]; + BlockIsRAM[i + bank] = TRUE; + BlockIsROM[i + bank] = FALSE; + } + } for (i = c + 8; i < c + 16; i++) - Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE] - 0x8000; - - for (i = c; i < c + 16; i++) { + Map[i + bank] = &PSRAM[(c << 11) % PSRAM_SIZE] - 0x8000; BlockIsRAM[i + bank] = TRUE; BlockIsROM[i + bank] = FALSE; } @@ -421,42 +471,149 @@ static void map_psram_mirror_sub (uint32 bank) } } -static void BSX_Map_PSRAM (void) +static void BSX_Map_PSRAM(void) { int c; - // Banks 70->77:0000-FFFF - // FIXME: could be toggled by $03 - for (c = 0; c < 0x80; c++) + if (!BSX.prevMMC[0x02]) { - Map[c + 0x700] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; - BlockIsRAM[c + 0x700] = TRUE; - BlockIsROM[c + 0x700] = FALSE; - } + //LoROM Mode + if (!BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 00-0F/80-8F + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x00); - // Banks 20->3F:6000-7FFF mirrors 70->77:6000-7FFF - for (c = 0x200; c < 0x400; c += 16) + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0x80); + } + else if (BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 20-2F/A0-AF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x20); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xA0); + } + else if (!BSX.prevMMC[0x05] && BSX.prevMMC[0x06]) + { + //Map PSRAM to 40-4F/C0-CF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x40); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xC0); + } + else + { + //Map PSRAM to 60-6F/E0-EF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x60); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xE0); + } + + //Map PSRAM to 70-7D/F0-FF + if (BSX.prevMMC[0x03]) + map_psram_mirror_sub(0x70); + + if (BSX.prevMMC[0x04]) + map_psram_mirror_sub(0xF0); + } + else { - Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; - Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; - BlockIsRAM[c + 6] = TRUE; - BlockIsRAM[c + 7] = TRUE; - BlockIsROM[c + 6] = FALSE; - BlockIsROM[c + 7] = FALSE; + //HiROM Mode + if (!BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 00-07/40-47 / 80-87/C0-C7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x00); + map_psram_mirror_sub(0x40); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0x80); + map_psram_mirror_sub(0xC0); + } + } + else if (BSX.prevMMC[0x05] && !BSX.prevMMC[0x06]) + { + //Map PSRAM to 10-17/50-57 / 90-97-D0-D7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x10); + map_psram_mirror_sub(0x50); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0x90); + map_psram_mirror_sub(0xD0); + } + } + else if (!BSX.prevMMC[0x05] && BSX.prevMMC[0x06]) + { + //Map PSRAM to 20-27/60-67 / A0-A7/E0-E7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x20); + map_psram_mirror_sub(0x60); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0xA0); + map_psram_mirror_sub(0xE0); + } + } + else + { + //Map PSRAM to 30-37/70-77 / B0-B7/F0-F7 + if (BSX.prevMMC[0x03]) + { + map_psram_mirror_sub(0x30); + map_psram_mirror_sub(0x70); + } + + if (BSX.prevMMC[0x04]) + { + map_psram_mirror_sub(0xB0); + map_psram_mirror_sub(0xF0); + } + } + + if (BSX.prevMMC[0x03]) + { + //Map PSRAM to 20->3F:6000-7FFF + for (c = 0x200; c < 0x400; c += 16) + { + Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; + Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; + BlockIsRAM[c + 6] = TRUE; + BlockIsRAM[c + 7] = TRUE; + BlockIsROM[c + 6] = FALSE; + BlockIsROM[c + 7] = FALSE; + } + } + + if (BSX.prevMMC[0x04]) + { + //Map PSRAM to A0->BF:6000-7FFF + for (c = 0xA00; c < 0xC00; c += 16) + { + Map[c + 6] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; + Map[c + 7] = &PSRAM[((c & 0x70) << 12) % PSRAM_SIZE]; + BlockIsRAM[c + 6] = TRUE; + BlockIsRAM[c + 7] = TRUE; + BlockIsROM[c + 6] = FALSE; + BlockIsROM[c + 7] = FALSE; + } + } } - - if (!BSX.MMC[0x05]) - // Banks 40->4F:0000-FFFF mirrors 70->77:0000-7FFF - map_psram_mirror_sub(0x40); - - if (!BSX.MMC[0x06]) - // Banks 50->5F:0000-FFFF mirrors 70->77:0000-7FFF - map_psram_mirror_sub(0x50); - - // FIXME - if (!BSX.MMC[0x03]) - // Banks 60->6F:0000-FFFF mirrors 70->77:0000-7FFF (?) - map_psram_mirror_sub(0x60); } static void BSX_Map_BIOS (void) @@ -464,7 +621,7 @@ static void BSX_Map_BIOS (void) int i,c; // Banks 00->1F:8000-FFFF - if (BSX.MMC[0x07]) + if (BSX.prevMMC[0x07]) { for (c = 0; c < 0x200; c += 16) { @@ -478,7 +635,7 @@ static void BSX_Map_BIOS (void) } // Banks 80->9F:8000-FFFF - if (BSX.MMC[0x08]) + if (BSX.prevMMC[0x08]) { for (c = 0; c < 0x200; c += 16) { @@ -508,39 +665,6 @@ static void BSX_Map_RAM (void) } } -static void BSX_Map_Dirty (void) -{ - // for the quick bank change - - int i, c; - - // Banks 00->1F and 80->9F:8000-FFFF - if (BSX.MMC[0x02]) - { - for (c = 0; c < 0x200; c += 16) - { - for (i = c + 8; i < c + 16; i++) - { - Map[i] = Map[i + 0x800] = &MapROM[(c << 12) % FlashSize]; - BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; - BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; - } - } - } - else - { - for (c = 0; c < 0x200; c += 16) - { - for (i = c + 8; i < c + 16; i++) - { - Map[i] = Map[i + 0x800] = &MapROM[(c << 11) % FlashSize] - 0x8000; - BlockIsRAM[i] = BlockIsRAM[i + 0x800] = BSX.write_enable; - BlockIsROM[i] = BlockIsROM[i + 0x800] = !BSX.write_enable; - } - } - } -} - static void BSX_Map (void) { #ifdef BSX_DEBUG @@ -551,42 +675,22 @@ static void BSX_Map (void) memcpy(BSX.prevMMC, BSX.MMC, sizeof(BSX.MMC)); - // Do a quick bank change - if (BSX.dirty2 && !BSX.dirty) - { - BSX_Map_Dirty(); - BSX_Map_BIOS(); + MapROM = FlashROM; + FlashSize = FLASH_SIZE; - BSX.dirty2 = FALSE; - - Memory.map_WriteProtectROM(); - return; - } - - if (BSX.MMC[0x01]) - { - MapROM = PSRAM; - FlashSize = PSRAM_SIZE; - } - else - { - MapROM = FlashROM; - FlashSize = FLASH_SIZE; - } - - BSX_Map_SNES(); - - if (BSX.MMC[0x02]) + if (BSX.prevMMC[0x02]) BSX_Map_HiROM(); else BSX_Map_LoROM(); + BSX_Map_FlashIO(); BSX_Map_PSRAM(); + + BSX_Map_SNES(); BSX_Map_SRAM(); BSX_Map_RAM(); BSX_Map_BIOS(); - BSX_Map_FlashIO(); BSX_Map_MMC(); // Monitor new register changes @@ -596,30 +700,26 @@ static void BSX_Map (void) Memory.map_WriteProtectROM(); } -static uint8 BSX_Get_Bypass_FlashIO (uint16 offset) +static uint8 BSX_Get_Bypass_FlashIO (uint32 offset) { - if (BSX.MMC[0x02]) - return (MapROM[offset]); + //For games other than BS-X + FlashROM = Memory.ROM + Multi.cartOffsetB; + + if (BSX.prevMMC[0x02]) + return (FlashROM[offset & 0x0FFFFF]); else - { - if (offset < 0x8000) - return (MapROM[offset]); - else - return (MapROM[offset - 0x8000]); - } + return (FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)]); } -static void BSX_Set_Bypass_FlashIO (uint16 offset, uint8 byte) +static void BSX_Set_Bypass_FlashIO (uint32 offset, uint8 byte) { - if (BSX.MMC[0x02]) - MapROM[offset] = byte; + //For games other than BS-X + FlashROM = Memory.ROM + Multi.cartOffsetB; + + if (BSX.prevMMC[0x02]) + FlashROM[offset & 0x0FFFFF] = FlashROM[offset & 0x0FFFFF] & byte; else - { - if (offset < 0x8000) - MapROM[offset] = byte; - else - MapROM[offset - 0x8000] = byte; - } + FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] = FlashROM[(offset & 0x1F0000) >> 1 | (offset & 0x7FFF)] & byte; } uint8 S9xGetBSX (uint32 address) @@ -629,43 +729,54 @@ uint8 S9xGetBSX (uint32 address) uint8 t = 0; // MMC - if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000)) + if ((bank >= 0x01 && bank <= 0x0E) && ((address & 0xF000) == 0x5000)) return (BSX.MMC[bank]); - // Flash IO - if (bank == 0xC0) + // Flash Mapping + + // default: read-through mode + t = BSX_Get_Bypass_FlashIO(address); + + // note: may be more registers, purposes unknown + switch (offset) { - // default: read-through mode - t = BSX_Get_Bypass_FlashIO(offset); + case 0x0002: + case 0x8002: + if (BSX.flash_bsr) + t = 0xC0; // Page Status Register + break; - // note: may be more registers, purposes unknown - switch (offset) - { - case 0x0002: - if (BSX.flash_enable) - t = 0x80; // status register? - break; + case 0x0004: + case 0x8004: + if (BSX.flash_gsr) + t = 0x82; // Global Status Register + break; - case 0x5555: - if (BSX.flash_enable) - t = 0x80; // ??? - break; + case 0x5555: + if (BSX.flash_enable) + t = 0x80; // ??? + break; - case 0xFF00: - case 0xFF02: - case 0xFF04: - case 0xFF06: - case 0xFF08: - case 0xFF0A: - case 0xFF0C: - case 0xFF0E: - case 0xFF10: - case 0xFF12: - // return flash vendor information - if (BSX.read_enable) - t = flashcard[offset - 0xFF00]; - break; - } + case 0xFF00: + case 0xFF02: + case 0xFF04: + case 0xFF06: + case 0xFF08: + case 0xFF0A: + case 0xFF0C: + case 0xFF0E: + case 0xFF10: + case 0xFF12: + // return flash vendor information + if (BSX.read_enable) + t = flashcard[offset - 0xFF00]; + break; + } + + if (BSX.flash_csr) + { + t = 0x80; // Compatible Status Register + BSX.flash_csr = false; } return (t); @@ -674,120 +785,236 @@ uint8 S9xGetBSX (uint32 address) void S9xSetBSX (uint8 byte, uint32 address) { uint8 bank = (address >> 16) & 0xFF; - uint16 offset = address & 0xFFFF; // MMC - if ((bank >= 0x01 && bank <= 0x0E) && (offset == 0x5000)) + if ((bank >= 0x01 && bank <= 0x0E) && ((address & 0xF000) == 0x5000)) { - switch (bank) + //Avoid updating the memory map when it is not needed + if (bank == 0x0E && BSX.dirty) { - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - if (BSX.MMC[bank] != byte) - { - BSX.MMC[bank] = byte; - BSX.dirty = TRUE; - } - break; - - case 0x07: - case 0x08: - if (BSX.MMC[bank] != byte) - { - BSX.MMC[bank] = byte; - BSX.dirty2 = TRUE; - } - break; - - case 0x0E: - BSX.MMC[bank] = byte; - if (byte && (BSX.dirty || BSX.dirty2)) - BSX_Map(); - break; + BSX_Map(); + BSX.dirty = FALSE; } + else if (bank != 0x0E && BSX.MMC[bank] != byte) + { + BSX.dirty = TRUE; + } + + BSX.MMC[bank] = byte; } // Flash IO - if (bank == 0xC0) + + // Write to Flash + if (BSX.write_enable) { - BSX.old_write = BSX.new_write; - BSX.new_write = address; - - // ???: double writes to the desired address will bypass - // flash registers - if (BSX.old_write == BSX.new_write && BSX.write_enable) - { - BSX_Set_Bypass_FlashIO(offset, byte); - return; - } - - // flash command handling - // note: incomplete - switch (offset) - { - case 0x0000: - BSX.flash_command <<= 8; - BSX.flash_command |= byte; - if ((BSX.flash_command & 0xFFFF) == 0x38D0) - { - // retrieve information about the flash card - BSX.flash_enable = TRUE; - BSX.read_enable = TRUE; - } - break; - - case 0x2AAA: - BSX.flash_command <<= 8; - BSX.flash_command |= byte; - break; - - case 0x5555: - BSX.flash_command <<= 8; - BSX.flash_command |= byte; - - switch (BSX.flash_command & 0xFFFFFF) - { - case 0xAA55F0: - // turn off flash i/o - BSX.flash_enable = FALSE; - BSX.write_enable = FALSE; - BSX.read_enable = FALSE; - break; - - case 0xAA55A0: - // enable writing to flash - BSX.old_write = 0; - BSX.new_write = 0; - BSX.flash_enable = TRUE; - BSX.write_enable = TRUE; - BSX_Map(); - break; - - case 0xAA5570: - // turn on write-protection - BSX.write_enable = FALSE; - BSX_Map(); - break; - - case 0xAA5580: - case 0xAA5510: - // ??? - break; - - } - - break; - } + BSX_Set_Bypass_FlashIO(address, byte); + BSX.write_enable = false; + return; } + + // Flash Command Handling + + //Memory Pack Type 1 & 3 & 4 + BSX.flash_command <<= 8; + BSX.flash_command |= byte; + + switch (BSX.flash_command & 0xFF) + { + case 0x00: + case 0xFF: + //Reset to normal + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = false; + BSX.flash_gsr = false; + BSX.read_enable = false; + BSX.write_enable = false; + BSX.flash_cmd_done = true; + break; + + case 0x10: + case 0x40: + //Write Byte + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = true; + BSX.flash_gsr = false; + BSX.read_enable = false; + BSX.write_enable = true; + BSX.flash_cmd_done = true; + break; + + case 0x50: + //Clear Status Register + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = false; + BSX.flash_gsr = false; + BSX.flash_cmd_done = true; + break; + + case 0x70: + //Read CSR + BSX.flash_enable = false; + BSX.flash_bsr = false; + BSX.flash_csr = true; + BSX.flash_gsr = false; + BSX.read_enable = false; + BSX.write_enable = false; + BSX.flash_cmd_done = true; + break; + + case 0x71: + //Read Extended Status Registers (Page and Global) + BSX.flash_enable = false; + BSX.flash_bsr = true; + BSX.flash_csr = false; + BSX.flash_gsr = true; + BSX.read_enable = false; + BSX.write_enable = false; + BSX.flash_cmd_done = true; + break; + + case 0x75: + //Show Page Buffer / Vendor Info + BSX.flash_csr = false; + BSX.read_enable = true; + BSX.flash_cmd_done = true; + break; + + case 0xD0: + //DO COMMAND + switch (BSX.flash_command & 0xFFFF) + { + case 0x20D0: //Block Erase + uint32 x; + for (x = 0; x < 0x10000; x++) { + //BSX_Set_Bypass_FlashIO(((address & 0xFF0000) + x), 0xFF); + if (BSX.MMC[0x02]) + FlashROM[(address & 0x0F0000) + x] = 0xFF; + else + FlashROM[((address & 0x1E0000) >> 1) + x] = 0xFF; + } + break; + + case 0xA7D0: //Chip Erase (ONLY IN TYPE 1 AND 4) + if ((flashcard[6] & 0xF0) == 0x10 || (flashcard[6] & 0xF0) == 0x40) + { + uint32 x; + for (x = 0; x < FLASH_SIZE; x++) { + //BSX_Set_Bypass_FlashIO(x, 0xFF); + FlashROM[x] = 0xFF; + } + } + break; + + case 0x38D0: //Flashcart Reset + break; + } + break; + } +} + +void S9xBSXSetStream1 (uint8 count) +{ + if (BSX.sat_stream1.is_open()) + BSX.sat_stream1.close(); //If Stream already opened for one file: Close it. + + char path[PATH_MAX + 1], name[PATH_MAX + 1]; + + strcpy(path, S9xGetDirectory(SAT_DIR)); + strcat(path, SLASH_STR); + + snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x2188 - BSXPPUBASE] | (BSX.PPU[0x2189 - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin + strcat(path, name); + + BSX.sat_stream1.clear(); + BSX.sat_stream1.open(path, std::ios::in | std::ios::binary); + if (BSX.sat_stream1.good()) + { + BSX.sat_stream1.seekg(0, BSX.sat_stream1.end); + long str1size = BSX.sat_stream1.tellg(); + BSX.sat_stream1.seekg(0, BSX.sat_stream1.beg); + float QueueSize = str1size / 22.; + BSX.sat_stream1_queue = (uint16)(ceil(QueueSize)); + BSX.PPU[0x218D - BSXPPUBASE] = 0; + BSX.sat_stream1_first = TRUE; + BSX.sat_stream1_loaded = TRUE; + } + else + { + BSX.sat_stream1_loaded = FALSE; + } +} + +void S9xBSXSetStream2 (uint8 count) +{ + if (BSX.sat_stream2.is_open()) + BSX.sat_stream2.close(); //If Stream already opened for one file: Close it. + + char path[PATH_MAX + 1], name[PATH_MAX + 1]; + + strcpy(path, S9xGetDirectory(SAT_DIR)); + strcat(path, SLASH_STR); + + snprintf(name, PATH_MAX + 1, "BSX%04X-%d.bin", (BSX.PPU[0x218E - BSXPPUBASE] | (BSX.PPU[0x218F - BSXPPUBASE] * 256)), count); //BSXHHHH-DDD.bin + strcat(path, name); + + BSX.sat_stream2.clear(); + BSX.sat_stream2.open(path, std::ios::in | std::ios::binary); + if (BSX.sat_stream2.good()) + { + BSX.sat_stream2.seekg(0, BSX.sat_stream2.end); + long str2size = BSX.sat_stream2.tellg(); + BSX.sat_stream2.seekg(0, BSX.sat_stream2.beg); + float QueueSize = str2size / 22.; + BSX.sat_stream2_queue = (uint16)(ceil(QueueSize)); + BSX.PPU[0x2193 - BSXPPUBASE] = 0; + BSX.sat_stream2_first = TRUE; + BSX.sat_stream2_loaded = TRUE; + } + else + { + BSX.sat_stream2_loaded = FALSE; + } +} + +uint8 S9xBSXGetRTC (void) +{ + //Get Time + time_t t; + struct tm *tmr; + + time(&t); + tmr = localtime(&t); + + BSX.test2192[0] = 0x00; + BSX.test2192[1] = 0x00; + BSX.test2192[2] = 0x00; + BSX.test2192[3] = 0x00; + BSX.test2192[4] = 0x10; + BSX.test2192[5] = 0x01; + BSX.test2192[6] = 0x01; + BSX.test2192[7] = 0x00; + BSX.test2192[8] = 0x00; + BSX.test2192[9] = 0x00; + BSX.test2192[10] = BSX_RTC.seconds = tmr->tm_sec; + BSX.test2192[11] = BSX_RTC.minutes = tmr->tm_min; + BSX.test2192[12] = BSX_RTC.hours = tmr->tm_hour; + BSX.test2192[13] = BSX_RTC.dayweek = (tmr->tm_wday) + 1; + BSX.test2192[14] = BSX_RTC.day = tmr->tm_mday; + BSX.test2192[15] = BSX_RTC.month = (tmr->tm_mon) + 1; + BSX_RTC.year = tmr->tm_year + 1900; + BSX.test2192[16] = (BSX_RTC.year) & 0xFF; + BSX.test2192[17] = (BSX_RTC.year) >> 8; + + t = BSX.test2192[BSX.out_index++]; + + if (BSX.out_index > 22) + BSX.out_index = 0; + + return t; } uint8 S9xGetBSXPPU (uint16 address) @@ -797,95 +1024,268 @@ uint8 S9xGetBSXPPU (uint16 address) // known read registers switch (address) { - // Test register low? (r/w) + //Stream 1 + // Logical Channel 1 + Data Structure (R/W) case 0x2188: t = BSX.PPU[0x2188 - BSXPPUBASE]; break; - // Test register high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x2189: t = BSX.PPU[0x2189 - BSXPPUBASE]; break; + // Prefix Count (R) case 0x218A: - t = BSX.PPU[0x218A - BSXPPUBASE]; + if (!BSX.sat_pf_latch1_enable || !BSX.sat_dt_latch1_enable) + { + t = 0; + break; + } + + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + t = 1; + break; + } + + if (BSX.sat_stream1_queue <= 0) + { + BSX.sat_stream1_count++; + S9xBSXSetStream1(BSX.sat_stream1_count - 1); + } + + if (!BSX.sat_stream1_loaded && (BSX.sat_stream1_count - 1) > 0) + { + BSX.sat_stream1_count = 1; + S9xBSXSetStream1(BSX.sat_stream1_count - 1); + } + + if (BSX.sat_stream1_loaded) + { + //Lock at 0x7F for bigger packets + if (BSX.sat_stream1_queue >= 128) + BSX.PPU[0x218A - BSXPPUBASE] = 0x7F; + else + BSX.PPU[0x218A - BSXPPUBASE] = BSX.sat_stream1_queue; + t = BSX.PPU[0x218A - BSXPPUBASE]; + } + else + t = 0; break; + // Prefix Latch (R/W) + case 0x218B: + if (BSX.sat_pf_latch1_enable) + { + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.PPU[0x218B - BSXPPUBASE] = 0x90; + } + + if (BSX.sat_stream1_loaded) + { + uint8 temp = 0; + if (BSX.sat_stream1_first) + { + // First packet + temp |= 0x10; + BSX.sat_stream1_first = FALSE; + } + + BSX.sat_stream1_queue--; + + if (BSX.sat_stream1_queue == 0) + { + //Last packet + temp |= 0x80; + } + + BSX.PPU[0x218B - BSXPPUBASE] = temp; + } + + BSX.PPU[0x218D - BSXPPUBASE] |= BSX.PPU[0x218B - BSXPPUBASE]; + t = BSX.PPU[0x218B - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // Data Latch (R/W) case 0x218C: - t = BSX.PPU[0x218C - BSXPPUBASE]; + if (BSX.sat_dt_latch1_enable) + { + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.PPU[0x218C - BSXPPUBASE] = S9xBSXGetRTC(); + } + else if (BSX.sat_stream1_loaded) + { + if (BSX.sat_stream1.eof()) + BSX.PPU[0x218C - BSXPPUBASE] = 0xFF; + else + BSX.PPU[0x218C - BSXPPUBASE] = BSX.sat_stream1.get(); + } + t = BSX.PPU[0x218C - BSXPPUBASE]; + } + else + { + t = 0; + } break; - // Transmission number low? (r/w) + // OR gate (R) + case 0x218D: + t = BSX.PPU[0x218D - BSXPPUBASE]; + BSX.PPU[0x218D - BSXPPUBASE] = 0; + break; + + //Stream 2 + // Logical Channel 1 + Data Structure (R/W) case 0x218E: t = BSX.PPU[0x218E - BSXPPUBASE]; break; - // Transmission number high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x218F: t = BSX.PPU[0x218F - BSXPPUBASE]; break; - // Status register? (r) + // Prefix Count (R) case 0x2190: - t = BSX.PPU[0x2190 - BSXPPUBASE]; + if (!BSX.sat_pf_latch2_enable || !BSX.sat_dt_latch2_enable) + { + t = 0; + break; + } + + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + t = 1; + break; + } + + if (BSX.sat_stream2_queue <= 0) + { + BSX.sat_stream2_count++; + S9xBSXSetStream2(BSX.sat_stream2_count - 1); + } + + if (!BSX.sat_stream2_loaded && (BSX.sat_stream2_count - 1) > 0) + { + BSX.sat_stream2_count = 1; + S9xBSXSetStream2(BSX.sat_stream2_count - 1); + } + + if (BSX.sat_stream2_loaded) + { + if (BSX.sat_stream2_queue >= 128) + BSX.PPU[0x2190 - BSXPPUBASE] = 0x7F; + else + BSX.PPU[0x2190 - BSXPPUBASE] = BSX.sat_stream2_queue; + t = BSX.PPU[0x2190 - BSXPPUBASE]; + } + else + t = 0; break; - // Data register? (r/w) + // Prefix Latch (R/W) + case 0x2191: + if (BSX.sat_pf_latch2_enable) + { + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.PPU[0x2191 - BSXPPUBASE] = 0x90; + } + + if (BSX.sat_stream2_loaded) + { + uint8 temp = 0; + if (BSX.sat_stream2_first) + { + // First packet + temp |= 0x10; + BSX.sat_stream2_first = FALSE; + } + + BSX.sat_stream2_queue--; + + if (BSX.sat_stream2_queue == 0) + { + //Last packet + temp |= 0x80; + } + + BSX.PPU[0x2191 - BSXPPUBASE] = temp; + } + + BSX.PPU[0x2193 - BSXPPUBASE] |= BSX.PPU[0x2191 - BSXPPUBASE]; + t = BSX.PPU[0x2191 - BSXPPUBASE]; + } + else + { + t = 0; + } + break; + + // Data Latch (R/W) case 0x2192: - t = BSX.PPU[0x2192 - BSXPPUBASE]; - - // test - t = BSX.test2192[BSX.out_index++]; - if (BSX.out_index == 32) - BSX.out_index = 0; - - BSX_RTC.ticks++; - if (BSX_RTC.ticks >= 1000) + if (BSX.sat_dt_latch2_enable) { - BSX_RTC.ticks = 0; - BSX_RTC.seconds++; + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.PPU[0x2192 - BSXPPUBASE] = S9xBSXGetRTC(); + } + else if (BSX.sat_stream2_loaded) + { + if (BSX.sat_stream2.eof()) + BSX.PPU[0x2192 - BSXPPUBASE] = 0xFF; + else + BSX.PPU[0x2192 - BSXPPUBASE] = BSX.sat_stream2.get(); + } + t = BSX.PPU[0x2192 - BSXPPUBASE]; } - if (BSX_RTC.seconds >= 60) + else { - BSX_RTC.seconds = 0; - BSX_RTC.minutes++; + t = 0; } - if (BSX_RTC.minutes >= 60) - { - BSX_RTC.minutes = 0; - BSX_RTC.hours++; - } - if (BSX_RTC.hours >= 24) - BSX_RTC.hours = 0; - - BSX.test2192[10] = BSX_RTC.seconds; - BSX.test2192[11] = BSX_RTC.minutes; - BSX.test2192[12] = BSX_RTC.hours; - break; - // Transmission status? (r/w) + // OR gate (R) case 0x2193: - // Data ready when bits 2/3 clear? - t = BSX.PPU[0x2193 - BSXPPUBASE] & ~0x0C; + t = BSX.PPU[0x2193 - BSXPPUBASE]; + BSX.PPU[0x2193 - BSXPPUBASE] = 0; break; - // Reset? (r/w) + //Other + // Satellaview LED / Stream Enable (R/W) [4bit] case 0x2194: t = BSX.PPU[0x2194 - BSXPPUBASE]; break; - // Unknown (r) + // Unknown + case 0x2195: + t = BSX.PPU[0x2195 - BSXPPUBASE]; + break; + + // Satellaview Status (R) case 0x2196: t = BSX.PPU[0x2196 - BSXPPUBASE]; break; - // Unknown (r/w) + // Soundlink Settings (R/W) case 0x2197: t = BSX.PPU[0x2197 - BSXPPUBASE]; break; - // Modem protocol? (r/w) + // Serial I/O - Serial Number (R/W) + case 0x2198: + t = BSX.PPU[0x2198 - BSXPPUBASE]; + break; + + // Serial I/O - Unknown (R/W) case 0x2199: t = BSX.PPU[0x2199 - BSXPPUBASE]; break; @@ -903,78 +1303,82 @@ void S9xSetBSXPPU (uint8 byte, uint16 address) // known write registers switch (address) { - // Test register low? (r/w) + //Stream 1 + // Logical Channel 1 + Data Structure (R/W) case 0x2188: + if (BSX.PPU[0x2188 - BSXPPUBASE] == byte) + { + BSX.sat_stream1_count = 0; + } BSX.PPU[0x2188 - BSXPPUBASE] = byte; break; - // Test register high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x2189: - BSX.PPU[0x2189 - BSXPPUBASE] = byte; - break; - - case 0x218A: - BSX.PPU[0x218A - BSXPPUBASE] = byte; + if (BSX.PPU[0x2188 - BSXPPUBASE] == (byte & 0x3F)) + { + BSX.sat_stream1_count = 0; + } + BSX.PPU[0x2189 - BSXPPUBASE] = byte & 0x3F; break; + // Prefix Latch (R/W) case 0x218B: - BSX.PPU[0x218B - BSXPPUBASE] = byte; + BSX.sat_pf_latch1_enable = (byte != 0); break; + // Data Latch (R/W) case 0x218C: - BSX.PPU[0x218C - BSXPPUBASE] = byte; + if (BSX.PPU[0x2188 - BSXPPUBASE] == 0 && BSX.PPU[0x2189 - BSXPPUBASE] == 0) + { + BSX.out_index = 0; + } + BSX.sat_dt_latch1_enable = (byte != 0); break; - // Transmission number low? (r/w) + //Stream 2 + // Logical Channel 1 + Data Structure (R/W) case 0x218E: + if (BSX.PPU[0x218E - BSXPPUBASE] == byte) + { + BSX.sat_stream2_count = 0; + } BSX.PPU[0x218E - BSXPPUBASE] = byte; break; - // Transmission number high? (r/w) + // Logical Channel 2 (R/W) [6bit] case 0x218F: - BSX.PPU[0x218F - BSXPPUBASE] = byte; - - // ? - BSX.PPU[0x218E - BSXPPUBASE] >>= 1; - BSX.PPU[0x218E - BSXPPUBASE] = BSX.PPU[0x218F - BSXPPUBASE] - BSX.PPU[0x218E - BSXPPUBASE]; - BSX.PPU[0x218F - BSXPPUBASE] >>= 1; - - BSX.PPU[0x2190 - BSXPPUBASE] = 0x80; // ? + if (BSX.PPU[0x218F - BSXPPUBASE] == (byte & 0x3F)) + { + BSX.sat_stream2_count = 0; + } + BSX.PPU[0x218F - BSXPPUBASE] = byte & 0x3F; break; - // Strobe assert? (w) + // Prefix Latch (R/W) case 0x2191: - BSX.PPU[0x2191 - BSXPPUBASE] = byte; - BSX.out_index = 0; + BSX.sat_pf_latch2_enable = (byte != 0); break; - // Data register? (r/w) + // Data Latch (R/W) case 0x2192: - BSX.PPU[0x2192 - BSXPPUBASE] = 0x01; // ? - BSX.PPU[0x2190 - BSXPPUBASE] = 0x80; // ? + if (BSX.PPU[0x218E - BSXPPUBASE] == 0 && BSX.PPU[0x218F - BSXPPUBASE] == 0) + { + BSX.out_index = 0; + } + BSX.sat_dt_latch2_enable = (byte != 0); break; - // Transmission status? (r/w) - case 0x2193: - BSX.PPU[0x2193 - BSXPPUBASE] = byte; - break; - - // Reset? (r/w) + //Other + // Satellaview LED / Stream Enable (R/W) [4bit] case 0x2194: - BSX.PPU[0x2194 - BSXPPUBASE] = byte; + BSX.PPU[0x2194 - BSXPPUBASE] = byte & 0x0F; break; - // Unknown (r/w) + // Soundlink Settings (R/W) case 0x2197: BSX.PPU[0x2197 - BSXPPUBASE] = byte; break; - - // Modem protocol? (r/w) - case 0x2199: - // Lots of modem strings written here when - // connection is lost or no uplink established - BSX.PPU[0x2199 - BSXPPUBASE] = byte; - break; } } @@ -987,8 +1391,7 @@ static bool8 BSX_LoadBIOS (void) { #ifdef GEKKO return FALSE; // We're not loading the BIOS! -#endif - +#else FILE *fp; char path[PATH_MAX + 1], name[PATH_MAX + 1]; bool8 r = FALSE; @@ -1024,13 +1427,22 @@ static bool8 BSX_LoadBIOS (void) #endif return (r); +#endif +} + +static bool8 is_BSX_BIOS (const uint8 *data, uint32 size) +{ + if (size == BIOS_SIZE && strncmp((char *) (data + 0x7FC0), "Satellaview BS-X ", 21) == 0) + return (TRUE); + else + return (FALSE); } void S9xInitBSX (void) { Settings.BS = FALSE; - if (!memcmp(&Memory.ROM[0x7FC0], "Satellaview BS-X ", 21)) + if (is_BSX_BIOS(Memory.ROM,Memory.CalculatedSize)) { // BS-X itself @@ -1067,7 +1479,13 @@ void S9xInitBSX (void) uint8 *header = r1 ? Memory.ROM + 0x7FC0 : Memory.ROM + 0xFFC0; FlashMode = (header[0x18] & 0xEF) == 0x20 ? FALSE : TRUE; - FlashSize = (header[0x19] & 0x20) ? PSRAM_SIZE : FLASH_SIZE; + FlashSize = FLASH_SIZE; + + // Fix Block Allocation Flags + // (for games that don't have it setup properly, + // for exemple when taken seperately from the upper memory of the Memory Pack, + // else the game will error out on BS-X) + for (; (((header[0x10] & 1) == 0) && header[0x10] != 0); (header[0x10] >>= 1)); #ifdef BSX_DEBUG for (int i = 0; i <= 0x1F; i++) @@ -1077,7 +1495,7 @@ void S9xInitBSX (void) BSX.bootup = Settings.BSXBootup; - if (!BSX_LoadBIOS()) + if (!BSX_LoadBIOS() && !is_BSX_BIOS(BIOSROM,BIOS_SIZE)) { BSX.bootup = FALSE; memset(BIOSROM, 0, BIOS_SIZE); @@ -1089,7 +1507,7 @@ void S9xInitBSX (void) { MapROM = NULL; FlashROM = Memory.ROM; - + /* time_t t; struct tm *tmr; @@ -1104,6 +1522,7 @@ void S9xInitBSX (void) #ifdef BSX_DEBUG printf("BS: Current Time: %02d:%02d:%02d\n", BSX_RTC.hours, BSX_RTC.minutes, BSX_RTC.seconds); #endif + */ SNESGameFixes.SRAMInitialValue = 0x00; } } @@ -1130,34 +1549,32 @@ void S9xResetBSX (void) memset(BSX.output, 0, sizeof(BSX.output)); // starting from the bios - if (BSX.bootup) - BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80; - else - { - BSX.MMC[0x02] = FlashMode ? 0x80: 0; + BSX.MMC[0x02] = BSX.MMC[0x03] = BSX.MMC[0x05] = BSX.MMC[0x06] = 0x80; + BSX.MMC[0x09] = BSX.MMC[0x0B] = 0x80; - // per bios: run from psram or flash card - if (FlashSize == PSRAM_SIZE) - { - memcpy(PSRAM, FlashROM, PSRAM_SIZE); + BSX.MMC[0x07] = BSX.MMC[0x08] = 0x80; + BSX.MMC[0x0E] = 0x80; - BSX.MMC[0x01] = 0x80; - BSX.MMC[0x03] = 0x80; - BSX.MMC[0x04] = 0x80; - BSX.MMC[0x0C] = 0x80; - BSX.MMC[0x0D] = 0x80; - } - else - { - BSX.MMC[0x03] = 0x80; - BSX.MMC[0x05] = 0x80; - BSX.MMC[0x06] = 0x80; - } + // default register values + BSX.PPU[0x2196 - BSXPPUBASE] = 0x10; + BSX.PPU[0x2197 - BSXPPUBASE] = 0x80; - BSX.MMC[0x0E] = 0x80; - } + // stream reset + BSX.sat_pf_latch1_enable = BSX.sat_dt_latch1_enable = FALSE; + BSX.sat_pf_latch2_enable = BSX.sat_dt_latch2_enable = FALSE; - BSX_Map(); + BSX.sat_stream1_loaded = BSX.sat_stream2_loaded = FALSE; + BSX.sat_stream1_first = BSX.sat_stream2_first = FALSE; + BSX.sat_stream1_count = BSX.sat_stream2_count = 0; + + if (BSX.sat_stream1.is_open()) + BSX.sat_stream1.close(); + + if (BSX.sat_stream2.is_open()) + BSX.sat_stream2.close(); + + if (Settings.BS) + BSX_Map(); } void S9xBSXPostLoadState (void) diff --git a/source/snes9x/tile.cpp b/source/snes9x/tile.cpp index e536008..fad941e 100644 --- a/source/snes9x/tile.cpp +++ b/source/snes9x/tile.cpp @@ -1413,7 +1413,7 @@ extern struct SLineMatrixData LineMatrixData[240]; GFX.S[Offset + 2 * N + 1] = MATH(GFX.ScreenColors[Pix], GFX.SubScreen[Offset + 2 * N], GFX.SubZBuffer[Offset + 2 * N]); \ if ((OffsetInLine + 2 * N ) != (SNES_WIDTH - 1) << 1) \ GFX.S[Offset + 2 * N + 2] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N + 2]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \ - if ((OffsetInLine + 2 * N) == 0) \ + if ((OffsetInLine + 2 * N) == 0 || (OffsetInLine + 2 * N) == GFX.RealPPL) \ GFX.S[Offset + 2 * N] = MATH((GFX.ClipColors ? 0 : GFX.SubScreen[Offset + 2 * N]), GFX.RealScreenColors[Pix], GFX.SubZBuffer[Offset + 2 * N]); \ GFX.DB[Offset + 2 * N] = GFX.DB[Offset + 2 * N + 1] = Z2; \ }