diff --git a/CHANGES.md b/CHANGES.md index 7ffa597..c51a6e5 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,11 @@ # Release notes +### v3.37 (released 2024-03-01) +- Bundles GBxCart RW v1.4/v1.4a firmware version R42+L11 (improves flash cart compatibility) +- Added support for F0095_4G_V1 with F0095H0 *(thanks Ausar)* +- Improved support for 256M29EWH (no PCB text) +- Confirmed and improved support for 512M29EWH (no PCB text) +- Minor bug fixes and improvements + ### v3.36 (released 2024-01-15) - Added support for DIY cart with 28F016S5 *(thanks alexbc2999)* - Fixed a problem with reading Sachen cartridges *(thanks xukkorz)* diff --git a/FlashGBX/FlashGBX.py b/FlashGBX/FlashGBX.py index 47e3c62..6f74fae 100644 --- a/FlashGBX/FlashGBX.py +++ b/FlashGBX/FlashGBX.py @@ -129,7 +129,7 @@ def main(portableMode=False): ap_cli2.add_argument("--dmg-romsize", choices=["auto", "32kb", "64kb", "128kb", "256kb", "512kb", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb"], type=str.lower, default="auto", help="set size of Game Boy cartridge ROM data") ap_cli2.add_argument("--dmg-mbc", type=str.lower, default="auto", help="set memory bank controller type of Game Boy cartridge") ap_cli2.add_argument("--dmg-savesize", choices=["auto", "4k", "16k", "64k", "256k", "512k", "1m", "eeprom2k", "eeprom4k", "tama5", "4m"], type=str.lower, default="auto", help="set size of Game Boy cartridge save data") - ap_cli2.add_argument("--agb-romsize", choices=["auto", "64kb", "128kb", "256kb", "512kb", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb", "64mb", "128mb", "256mb"], type=str.lower, default="auto", help="set size of Game Boy Advance cartridge ROM data") + ap_cli2.add_argument("--agb-romsize", choices=["auto", "64kb", "128kb", "256kb", "512kb", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb", "64mb", "128mb", "256mb", "512mb"], type=str.lower, default="auto", help="set size of Game Boy Advance cartridge ROM data") ap_cli2.add_argument("--agb-savetype", choices=["auto", "eeprom4k", "eeprom64k", "sram256k", "flash512k", "flash1m", "dacs8m", "sram512k", "sram1m"], type=str.lower, default="auto", help="set type of Game Boy Advance cartridge save data") ap_cli2.add_argument("--store-rtc", action="store_true", help="store RTC register values if supported") ap_cli2.add_argument("--ignore-bad-header", action="store_true", help="don’t stop if invalid data found in cartridge header data") diff --git a/FlashGBX/FlashGBX_CLI.py b/FlashGBX/FlashGBX_CLI.py index d01772f..f8cc45b 100644 --- a/FlashGBX/FlashGBX_CLI.py +++ b/FlashGBX/FlashGBX_CLI.py @@ -593,7 +593,7 @@ def DetectCartridge(self, limitVoltage=False): header = self.CONN.ReadInfo() self.ReadCartridge(header) ret = self.CONN.DetectCartridge(limitVoltage=limitVoltage, checkSaveType=True) - (header, _, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id) = ret + (header, _, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id, detected_size) = ret # Save Type if save_type is None: @@ -645,7 +645,10 @@ def DetectCartridge(self, limitVoltage=False): (flash_id, cfi_s, _) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=supp_cart_types[1][cart_type]) msg_cart_type_s = "Cartridge Type: Supported flash cartridge – compatible with:\n{:s}\n".format(msg_cart_type) - if "flash_size" in supp_cart_types[1][cart_type_id]: + if detected_size > 0: + size = detected_size + msg_flash_size_s = "ROM Size: {:s}\n".format(Util.formatFileSize(size=size, asInt=True)) + elif "flash_size" in supp_cart_types[1][cart_type_id]: size = supp_cart_types[1][cart_type_id]["flash_size"] msg_flash_size_s = "ROM Size: {:s}\n".format(Util.formatFileSize(size=size, asInt=True)) @@ -741,7 +744,7 @@ def BackupROM(self, args, header): if args.agb_romsize == "auto": rom_size = header["rom_size"] else: - sizes = [ "auto", "64kb", "128kb", "256kb", "512kb", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb", "64mb", "128mb", "256mb" ] + sizes = [ "auto", "64kb", "128kb", "256kb", "512kb", "1mb", "2mb", "4mb", "8mb", "16mb", "32mb", "64mb", "128mb", "256mb", "512mb" ] rom_size = Util.AGB_Header_ROM_Sizes_Map[sizes.index(args.agb_romsize) - 1] if args.path != "auto": @@ -855,8 +858,8 @@ def FlashROM(self, args, header): path = args.path try: - if os.path.getsize(path) > 0x10000000: # reject too large files to avoid exploding RAM - print("{:s}ROM files bigger than 256 MiB are not supported.{:s}".format(ANSI.RED, ANSI.RESET)) + if os.path.getsize(path) > 0x20000000: # reject too large files to avoid exploding RAM + print("{:s}ROM files bigger than 512 MiB are not supported.{:s}".format(ANSI.RED, ANSI.RESET)) return elif os.path.getsize(path) < 0x400: print("{:s}ROM files smaller than 1 KiB are not supported.{:s}".format(ANSI.RED, ANSI.RESET)) diff --git a/FlashGBX/FlashGBX_GUI.py b/FlashGBX/FlashGBX_GUI.py index 55bb7fe..a6616df 100644 --- a/FlashGBX/FlashGBX_GUI.py +++ b/FlashGBX/FlashGBX_GUI.py @@ -690,7 +690,7 @@ def ConnectDevice(self): dev.SetWriteDelay(enable=str(self.SETTINGS.value("WriteDelay", default="disabled")).lower() == "enabled") qt_app.processEvents() self.CONN = dev - self.CONN.SetTimeout(float(self.SETTINGS.value("SerialTimeout", default="0.5"))) + self.CONN.SetTimeout(float(self.SETTINGS.value("SerialTimeout", default="1"))) self.optDMG.setAutoExclusive(False) self.optAGB.setAutoExclusive(False) if "DMG" in self.CONN.GetSupprtedModes(): @@ -1258,8 +1258,8 @@ def FlashROM(self, dpath=""): if os.path.getsize(path) == 0: QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The selected ROM file is empty.", QtWidgets.QMessageBox.Ok) return - if os.path.getsize(path) > 0x10000000: # reject too large files to avoid exploding RAM - QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "ROM files bigger than 256 MiB are not supported.", QtWidgets.QMessageBox.Ok) + if os.path.getsize(path) > 0x20000000: # reject too large files to avoid exploding RAM + QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "ROM files bigger than 512 MiB are not supported.", QtWidgets.QMessageBox.Ok) return with open(path, "rb") as file: @@ -2339,7 +2339,7 @@ def DetectCartridge(self, canSkipMessage=False): self.DisconnectDevice() cart_type = None else: - (header, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id) = ret + (header, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, _, flash_id, detected_size) = ret # Save Type if not canSkipMessage: @@ -2436,7 +2436,10 @@ def DetectCartridge(self, canSkipMessage=False): msg_cart_type_s_detail = "Compatible Cartridge Types:
{:s}
".format(msg_cart_type) found_supported = True - if "flash_size" in supp_cart_types[1][cart_type_id]: + if detected_size > 0: + size = detected_size + msg_flash_size_s = "ROM Size: {:s}
".format(Util.formatFileSize(size=size, asInt=True)) + elif "flash_size" in supp_cart_types[1][cart_type_id]: size = supp_cart_types[1][cart_type_id]["flash_size"] msg_flash_size_s = "ROM Size: {:s}
".format(Util.formatFileSize(size=size, asInt=True)) diff --git a/FlashGBX/Flashcart.py b/FlashGBX/Flashcart.py index d1ed87a..8f8be1c 100644 --- a/FlashGBX/Flashcart.py +++ b/FlashGBX/Flashcart.py @@ -133,6 +133,10 @@ def GetFlashSize(self, default=False): if "flash_size" not in self.CONFIG: return default return self.CONFIG["flash_size"] + def SetFlashSize(self, size): + if "flash_size" not in self.CONFIG: return + self.CONFIG["flash_size"] = size + def GetBufferSize(self): if "buffer_size" in self.CONFIG: return self.CONFIG["buffer_size"] @@ -450,11 +454,17 @@ def SectorErase(self, pos=0, buffer_pos=0): else: return self.CONFIG["sector_size"] + def HasBanks(self): + return "flash_bank_select_type" in self.CONFIG + def SelectBankROM(self, index): if "flash_bank_select_type" not in self.CONFIG: return False + dprint(f"Setting flash bank to {index:d}") if self.CONFIG["flash_bank_select_type"] == 1: - dprint(self.GetName(), "|", index) + index = index & 0xF self.CartWrite([[2, index << 4]], sram=True) + self.CartWrite([[3, 0x40]], sram=True) + self.CartWrite([[4, 0x00]], sram=True) return True elif self.CONFIG["flash_bank_select_type"] == 2: # Flash2Advance Ultra bank1 = 0 if index < 4 else 0x10 diff --git a/FlashGBX/Util.py b/FlashGBX/Util.py index 1242926..da3590e 100644 --- a/FlashGBX/Util.py +++ b/FlashGBX/Util.py @@ -7,19 +7,19 @@ # Common constants APPNAME = "FlashGBX" -VERSION_PEP440 = "3.36" +VERSION_PEP440 = "3.37" VERSION = "v{:s}".format(VERSION_PEP440) -VERSION_TIMESTAMP = 1705328830 +VERSION_TIMESTAMP = 1709318129 DEBUG = False DEBUG_LOG = [] APP_PATH = "" CONFIG_PATH = "" -AGB_Header_ROM_Sizes = [ "64 KiB", "128 KiB", "256 KiB", "512 KiB", "1 MiB", "2 MiB", "4 MiB", "8 MiB", "16 MiB", "32 MiB", "64 MiB", "128 MiB", "256 MiB" ] -AGB_Header_ROM_Sizes_Map = [ 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000 ] +AGB_Header_ROM_Sizes = [ "64 KiB", "128 KiB", "256 KiB", "512 KiB", "1 MiB", "2 MiB", "4 MiB", "8 MiB", "16 MiB", "32 MiB", "64 MiB", "128 MiB", "256 MiB", "512 MiB" ] +AGB_Header_ROM_Sizes_Map = [ 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000 ] AGB_Header_Save_Types = [ "None", "4K EEPROM (512 Bytes)", "64K EEPROM (8 KiB)", "256K SRAM/FRAM (32 KiB)", "512K FLASH (64 KiB)", "1M FLASH (128 KiB)", "8M DACS (1 MiB)", "Unlicensed 512K SRAM (64 KiB)", "Unlicensed 1M SRAM (128 KiB)", "Unlicensed Batteryless SRAM" ] AGB_Header_Save_Sizes = [ 0, 512, 8192, 32768, 65536, 131072, 1048576, 65536, 131072, 0 ] -AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:"Macronix MX29L512", 0x321B:"Panasonic MN63F805MNP", 0xC209:"Macronix MX29L010", 0x6213:"SANYO LE26FV10N1TS", 0xBF5B:"Unlicensed SST SST49LF080A", 0xFFFF:"Unlicensed 0xFFFF" } +AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:"Macronix MX29L512", 0x321B:"Panasonic MN63F805MNP", 0xC209:"Macronix MX29L010", 0x6213:"SANYO LE26FV10N1TS", 0xBF5B:"Unlicensed SST49LF080A", 0xFFFF:"Unlicensed 0xFFFF" } AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 0x20000, 0x20000, 0x20000, 0x20000 ] DMG_Header_Mapper = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+SRAM+BATTERY', 0x0F:'MBC3+RTC+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 0x110:'MBC30+RTC+SRAM+BATTERY', 0x12:'MBC3+SRAM', 0x13:'MBC3+SRAM+BATTERY', 0x19:'MBC5', 0x1A:'MBC5+SRAM', 0x1B:'MBC5+SRAM+BATTERY', 0x1C:'MBC5+RUMBLE', 0x1E:'MBC5+RUMBLE+SRAM+BATTERY', 0x20:'MBC6+SRAM+FLASH+BATTERY', 0x22:'MBC7+ACCELEROMETER+EEPROM', 0x101:'MBC1M', 0x103:'MBC1M+SRAM+BATTERY', 0x0B:'MMM01', 0x0D:'MMM01+SRAM+BATTERY', 0xFC:'MAC-GBD+SRAM+BATTERY', 0x105:'G-MMC1+SRAM+BATTERY', 0x104:'M161', 0xFF:'HuC-1+IR+SRAM+BATTERY', 0xFE:'HuC-3+RTC+SRAM+BATTERY', 0xFD:'TAMA5+RTC+EEPROM', 0x201:'Unlicensed 256M Mapper', 0x202:'Unlicensed Wisdom Tree Mapper', 0x203:'Unlicensed Xploder GB Mapper', 0x204:'Unlicensed Sachen Mapper', 0x205:'Unlicensed Datel Orbit V2 Mapper' } @@ -314,30 +314,27 @@ def formatProgressTimeShort(sec): sec %= 60 return "{:02d}:{:02d}:{:02d}".format(int(hr), int(min), int(sec)) -def formatProgressTime(sec, asFloat=False): - if int(sec) == 1: - return "{:d} second".format(int(sec)) - elif sec < 60: - if sec < 1 and asFloat: - return "{:.2f} seconds".format(sec) - else: - return "{:d} seconds".format(int(sec)) - elif int(sec) == 60: - return "1 minute" - else: - min = int(sec / 60) - sec = int(sec % 60) - s = str(min) + " " - if min == 1: - s = s + "minute" - else: - s = s + "minutes" - s = s + ", " + str(sec) + " " - if sec == 1: - s = s + "second" - else: - s = s + "seconds" - return s +def formatProgressTime(seconds, asFloat=False): + hr = int(seconds // 3600) + min = int((seconds // 60) - (60 * hr)) + sec = seconds % 60 + + if seconds < 1 and asFloat: + return "{:.2f} seconds".format(seconds) + s = "" + if hr > 0: + s += "{:d} hour".format(hr) + if hr != 1: s += "s" + s += ", " + if min > 0: + s += "{:d} minute".format(min) + if min != 1: s += "s" + s += ", " + if sec >= 1 or seconds < 60: + s += "{:d} second".format(int(sec)) + if sec != 1: s += "s" + s += ", " + return s[:-2] def formatPathOS(path, end_sep=False): if platform.system() == "Windows": diff --git a/FlashGBX/config/db_AGB.json b/FlashGBX/config/db_AGB.json index 9778580..6f531f2 100644 --- a/FlashGBX/config/db_AGB.json +++ b/FlashGBX/config/db_AGB.json @@ -489,8 +489,8 @@ "gc": "A2YE", "rc": 3754462526, "rs": 4194304, - "st": 4, - "ss": 65536, + "st": 0, + "ss": 0, "lg": "En,Fr,De,Es,It", "rg": "USA" }, @@ -21226,11 +21226,11 @@ "lg": "Ja", "rg": "Japan" }, - "f71e3df4bf5f4c9000b9e3c931696bf237e6cac6": { + "414992293e84502d31cbc612234fbb15427e9a81": { "gn": "Fear Factor - Unleashed", "ne": "(USA)", "gc": "BFUE", - "rc": 310993820, + "rc": 3214000765, "rs": 8388608, "st": 1, "ss": 512, diff --git a/FlashGBX/config/db_DMG.json b/FlashGBX/config/db_DMG.json index c25fa57..4fa6199 100644 --- a/FlashGBX/config/db_DMG.json +++ b/FlashGBX/config/db_DMG.json @@ -207,6 +207,15 @@ "lg": "En,Fr,De,Es,It", "rg": "Europe" }, + "70d6c1b7b0dab7f6dec9dbc4eae454a19a37d6cd": { + "gn": "Trip World DX", + "ne": "(USA) (Limited Run Games)", + "gc": "", + "rc": 2937566187, + "rs": 524288, + "lg": "En", + "rg": "USA" + }, "bdf78e28adb73b3bec1c232bb5102cd9cb6128c5": { "gn": "Tutty", "ne": "(Europe) (Demo)", diff --git a/FlashGBX/config/fc_AGB_F0095H0.txt b/FlashGBX/config/fc_AGB_F0095H0.txt new file mode 100644 index 0000000..893ae7a --- /dev/null +++ b/FlashGBX/config/fc_AGB_F0095H0.txt @@ -0,0 +1,52 @@ +{ + "type":"AGB", + "names":[ + "F0095_4G_V1 with F0095H0" + ], + "flash_ids":[ + [ 0x8A, 0x00, 0xB0, 0x88 ] + ], + "voltage":3.3, + "flash_size":0x20000000, + "flash_bank_size":0x2000000, + "flash_bank_select_type":1, + "sector_size":0x40000, + "reset_every":0x400000, + "buffer_size":1024, + "command_set":"INTEL", + "commands":{ + "reset":[ + [ 0, 0x50 ], + [ 0, 0xFF ] + ], + "read_identifier":[ + [ 0, 0x90 ] + ], + "sector_erase":[ + [ "SA", 0x60 ], + [ "SA", 0xD0 ], + [ "SA", 0x20 ], + [ "SA", 0xD0 ] + ], + "sector_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ "SA", 0x80, 0x80 ] + ], + "buffer_write":[ + [ "SA", 0xEA ], + [ "SA", "BS" ], + [ "PA", "PD" ], + [ "SA", 0xD0 ], + [ "SA", 0xFF ] + ], + "buffer_write_wait_for":[ + [ "SA", 0x80, 0x80 ], + [ null, null, null ], + [ null, null, null ], + [ "SA", 0x80, 0x80 ], + [ null, null, null ] + ] + } +} diff --git a/FlashGBX/config/fc_DMG_256M29EWH.txt b/FlashGBX/config/fc_DMG_256M29EWH.txt index 1de6ab9..b6c6f48 100644 --- a/FlashGBX/config/fc_DMG_256M29EWH.txt +++ b/FlashGBX/config/fc_DMG_256M29EWH.txt @@ -1,9 +1,11 @@ { "type":"DMG", "names":[ - "256M29EWH (no PCB text)" + "256M29EWH (no PCB text)", + "512M29EWH (no PCB text)" ], "flash_ids":[ + [ 0x8A, 0x8A, 0x7D, 0x7D ], [ 0x8A, 0x8A, 0x7D, 0x7D ] ], "voltage":3.3, @@ -13,6 +15,7 @@ "first_bank":1, "chip_erase_timeout":120, "sector_size_from_cfi":true, + "buffer_size":256, "reset_every":0x800000, "mbc":0x201, "write_pin":"WR", @@ -59,7 +62,23 @@ [ null, null, null ], [ null, null, null ], [ null, null, null ], - [ "SA", 0xFF, 0xFF ] + [ "SA", 0x80, 0x80 ] + ], + "buffer_write":[ + [ 0xAAA, 0xA9 ], + [ 0x555, 0x56 ], + [ "SA", 0x26 ], + [ "SA", "BS" ], + [ "PA", "PD" ], + [ "SA", 0x2A ] + ], + "buffer_write_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ "SA", "PD", 0xFF ] ], "single_write":[ [ 0xAAA, 0xA9 ], diff --git a/FlashGBX/config/fc_DMG_28F016S5.txt b/FlashGBX/config/fc_DMG_28F016S5.txt new file mode 100644 index 0000000..1ace364 --- /dev/null +++ b/FlashGBX/config/fc_DMG_28F016S5.txt @@ -0,0 +1,43 @@ +{ + "type":"DMG", + "names":[ + "DIY cart with 28F016S5 @ AUDIO" + ], + "flash_ids":[ + [ 0x89, 0xAA ] + ], + "voltage":5, + "flash_size":0x200000, + "sector_size":0x10000, + "start_addr":0, + "first_bank":1, + "write_pin":"AUDIO", + "mbc":"manual", + "command_set":"INTEL", + "commands":{ + "reset":[ + [ 0, 0xFF ] + ], + "read_identifier":[ + [ 0, 0x90 ] + ], + "sector_erase":[ + [ 0x4000, 0x20 ], + [ 0x4000, 0xD0 ] + ], + "sector_erase_wait_for":[ + [ null, null, null ], + [ 0x4000, 0x80, 0x80 ] + ], + "single_write":[ + [ "PA", 0x70 ], + [ "PA", 0x40 ], + [ "PA", "PD" ] + ], + "single_write_wait_for":[ + [ 0, 0x80, 0x80 ], + [ null, null, null ], + [ null, null, null ] + ] + } +} diff --git a/FlashGBX/config/fc_DMG_Generic_AUDIO_555_A9.txt b/FlashGBX/config/fc_DMG_Generic_AUDIO_555_A9.txt new file mode 100644 index 0000000..badb241 --- /dev/null +++ b/FlashGBX/config/fc_DMG_Generic_AUDIO_555_A9.txt @@ -0,0 +1,54 @@ +{ + "type":"DMG", + "names":[ + "Generic Flash Cartridge (AUDIO/555/A9)" + ], + "voltage":3.3, + "voltage_variants":true, + "start_addr":0, + "first_bank":1, + "write_pin":"AUDIO", + "chip_erase_timeout":120, + "command_set":"AMD", + "commands":{ + "reset":[ + [ 0, 0xF0 ] + ], + "read_identifier":[ + [ 0x555, 0xA9 ], + [ 0x2AA, 0x56 ], + [ 0x555, 0x90 ] + ], + "read_cfi":[ + [ 0x555, 0x98 ] + ], + "chip_erase":[ + [ 0x555, 0xA9 ], + [ 0x2AA, 0x56 ], + [ 0x555, 0x80 ], + [ 0x555, 0xA9 ], + [ 0x2AA, 0x56 ], + [ 0x555, 0x10 ] + ], + "chip_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ 0, 0xFF, 0xFF ] + ], + "single_write":[ + [ 0x555, 0xA9 ], + [ 0x2AA, 0x56 ], + [ 0x555, 0xA0 ], + [ "PA", "PD" ] + ], + "single_write_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ] + ] + } +} diff --git a/FlashGBX/config/fc_DMG_Generic_AUDIO_AAA_A9.txt b/FlashGBX/config/fc_DMG_Generic_AUDIO_AAA_A9.txt new file mode 100644 index 0000000..2058292 --- /dev/null +++ b/FlashGBX/config/fc_DMG_Generic_AUDIO_AAA_A9.txt @@ -0,0 +1,54 @@ +{ + "type":"DMG", + "names":[ + "Generic Flash Cartridge (AUDIO/AAA/A9)" + ], + "voltage":3.3, + "voltage_variants":true, + "start_addr":0, + "first_bank":1, + "write_pin":"AUDIO", + "chip_erase_timeout":120, + "command_set":"AMD", + "commands":{ + "reset":[ + [ 0, 0xF0 ] + ], + "read_identifier":[ + [ 0xAAA, 0xA9 ], + [ 0x555, 0x56 ], + [ 0xAAA, 0x90 ] + ], + "read_cfi":[ + [ 0xAAA, 0x98 ] + ], + "chip_erase":[ + [ 0xAAA, 0xA9 ], + [ 0x555, 0x56 ], + [ 0xAAA, 0x80 ], + [ 0xAAA, 0xA9 ], + [ 0x555, 0x56 ], + [ 0xAAA, 0x10 ] + ], + "chip_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ 0, 0xFF, 0xFF ] + ], + "single_write":[ + [ 0xAAA, 0xA9 ], + [ 0x555, 0x56 ], + [ 0xAAA, 0xA0 ], + [ "PA", "PD" ] + ], + "single_write_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ] + ] + } +} diff --git a/FlashGBX/config/fc_DMG_Sillyhatday_4MB_2x29F016.txt b/FlashGBX/config/fc_DMG_Sillyhatday_4MB_2x29F016.txt index 6468656..a00d363 100644 --- a/FlashGBX/config/fc_DMG_Sillyhatday_4MB_2x29F016.txt +++ b/FlashGBX/config/fc_DMG_Sillyhatday_4MB_2x29F016.txt @@ -1,7 +1,7 @@ { "type":"DMG", "names":[ - "Sillyhatday MBC5-DUAL-FLASH-4/8MB" + "Sillyhatday MBC5-DUAL-FLASH-4MB" ], "voltage":5, "flash_size":0x800000, diff --git a/FlashGBX/config/fc_DMG_Sillyhatday_8MB_4x29F016.txt b/FlashGBX/config/fc_DMG_Sillyhatday_8MB_4x29F016.txt new file mode 100644 index 0000000..3034dbc --- /dev/null +++ b/FlashGBX/config/fc_DMG_Sillyhatday_8MB_4x29F016.txt @@ -0,0 +1,111 @@ +{ + "type":"DMG", + "names":[ + "Sillyhatday MBC5-QUAD-FLASH-8MB" + ], + "voltage":5, + "flash_size":0x800000, + "start_addr":0x4000, + "first_bank":0, + "write_pin":"AUDIO", + "chip_erase_timeout":120, + "mbc":0x1B, + "command_set":"AMD", + "commands":{ + "reset":[ + [ 0x4000, 0xF0 ] + ], + "read_identifier":[ + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x90 ] + ], + "read_cfi":[ + [ 0x4AAA, 0x98 ] + ], + "chip_erase":[ + [ 0x3000, 0x00, "WR" ], + [ 0x2100, 0x00, "WR" ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x80 ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x10 ], + [ 0x3000, 0x00, "WR" ], + [ 0x2100, 0x80, "WR" ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x80 ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x10 ], + [ 0x3000, 0x01, "WR" ], + [ 0x2100, 0x00, "WR" ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x80 ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x10 ], + [ 0x3000, 0x01, "WR" ], + [ 0x2100, 0x80, "WR" ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x80 ], + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0x10 ], + [ 0x3000, 0x00, "WR" ], + [ 0x2100, 0x00, "WR" ] + ], + "chip_erase_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ 0x4000, 0xFF, 0xFF ], + [ null, null, null ], + [ 0x4000, 0xFF, 0xFF ] + ], + "single_write":[ + [ 0x4555, 0xAA ], + [ 0x42AA, 0x55 ], + [ 0x4555, 0xA0 ], + [ "PA", "PD" ] + ], + "single_write_wait_for":[ + [ null, null, null ], + [ null, null, null ], + [ null, null, null ], + [ null, null, null ] + ] + } +} diff --git a/FlashGBX/config/fc_DMG_iG_8MB.txt b/FlashGBX/config/fc_DMG_iG_8MB.txt index 1f53f00..1743b23 100644 --- a/FlashGBX/config/fc_DMG_iG_8MB.txt +++ b/FlashGBX/config/fc_DMG_iG_8MB.txt @@ -2,7 +2,7 @@ "type":"DMG", "names":[ "insideGadgets 8 MiB", - "FunnyPlaying MidnightTrace 4 MiB Flash Cart" + "FunnyPlaying MidnightTrace Flash Cart" ], "flash_ids":[ [ 0x01, 0x01, 0x7E, 0x7E ], diff --git a/FlashGBX/hw_GBxCartRW.py b/FlashGBX/hw_GBxCartRW.py index e1e22d8..5cfebcc 100644 --- a/FlashGBX/hw_GBxCartRW.py +++ b/FlashGBX/hw_GBxCartRW.py @@ -17,7 +17,7 @@ class GbxDevice: DEVICE_NAME = "GBxCart RW" DEVICE_MIN_FW = 1 DEVICE_MAX_FW = 10 - DEVICE_LATEST_FW_TS = { 4:1686057604, 5:1681900614, 6:1681900614 } + DEVICE_LATEST_FW_TS = { 4:1709317610, 5:1707258786, 6:1707258786 } DEVICE_CMD = { "NULL":0x30, @@ -47,6 +47,7 @@ class GbxDevice: "CLK_LOW":0xAA, "ENABLE_PULLUPS":0xAB, "DISABLE_PULLUPS":0xAC, + "GET_VARIABLE":0xAD, "DMG_CART_READ":0xB1, "DMG_CART_WRITE":0xB2, "DMG_CART_WRITE_SRAM":0xB3, @@ -116,7 +117,7 @@ class GbxDevice: BAUDRATE = 1000000 MAX_BUFFER_READ = 0x2000 MAX_BUFFER_WRITE = 0x400 - DEVICE_TIMEOUT = 0.75 + DEVICE_TIMEOUT = 1 WRITE_DELAY = False READ_ERRORS = 0 @@ -405,7 +406,8 @@ def SetWriteDelay(self, enable=True): dprint("Setting Write Delay to", enable) self.WRITE_DELAY = enable - def SetTimeout(self, seconds=0.5): + def SetTimeout(self, seconds=1): + if seconds < 1: seconds = 1 self.DEVICE_TIMEOUT = seconds self.DEVICE.timeout = self.DEVICE_TIMEOUT @@ -420,11 +422,10 @@ def wait_for_ack(self, values=None): if "from_user" in self.CANCEL_ARGS and self.CANCEL_ARGS["from_user"]: return False elif buffer is False: - print("{:s}Error: The USB connection timed out.{:s}".format(ANSI.RED, ANSI.RESET)) - dprint("Timeout error ({:s}(), line {:d})".format(stack.name, stack.lineno)) + dprint("Timeout error ({:s}(), line {:d}): {:f}".format(stack.name, stack.lineno, self.DEVICE.timeout)) self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"A timeout error has occured at {:s}() in line {:d}. Please make sure that the cartridge contacts are clean, re-connect the device and try again from the beginning.".format(stack.name, stack.lineno)}) else: - dprint("Communication error ({:s}(), line {:d})".format(stack.name, stack.lineno)) + dprint("Communication error ({:s}(), line {:d}): {:s}".format(stack.name, stack.lineno, str(buffer))) self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"A communication error has occured at {:s}() in line {:d}. Please make sure that the cartridge contacts are clean, re-connect the device and try again from the beginning.".format(stack.name, stack.lineno)}) self.ERROR = True self.CANCEL = True @@ -839,13 +840,13 @@ def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=True): ret = self.AutoDetectFlash(limitVoltage=limitVoltage) if ret is False: return False - (cart_types, cart_type_id, flash_id, cfi_s, cfi) = ret + (cart_types, cart_type_id, flash_id, cfi_s, cfi, detected_size) = ret supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values()) cart_type = supported_carts[cart_type_id] if self.MODE == "DMG" and "command_set" in cart_type and cart_type["command_set"] == "DMG-MBC5-32M-FLASH": checkSaveType = False elif self.MODE == "AGB" and "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] == 1: - save_size == 65536 + save_size = 65536 save_type = 7 checkSaveType = False elif self.MODE == "AGB" and "flash_bank_select_type" in cart_type and cart_type["flash_bank_select_type"] > 1: @@ -875,14 +876,14 @@ def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=True): if mbc == 0x20: # MBC6 save_size = 1081344 save_type = 0x104 - return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id) + return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id, detected_size) elif mbc == 0x22: # MBC7 save_type = 0x102 save_size = 512 elif mbc == 0xFD: # TAMA5 save_size = 32 save_type = 0x103 - return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id) + return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id, detected_size) args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':save_type, 'rtc':False } elif self.MODE == "AGB": args = { 'mode':2, 'path':None, 'mbc':mbc, 'save_type':8, 'rtc':False } @@ -997,7 +998,7 @@ def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=True): self._write(self.DEVICE_CMD["DMG_MBC_RESET"], wait=True) self.INFO["last_action"] = 0 self.INFO["action"] = None - return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id) + return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id, detected_size) def CheckBatterylessSRAM(self): bl_size = None @@ -1713,6 +1714,7 @@ def AutoDetectFlash(self, limitVoltage=False): # Check flash size flash_type_id = 0 + detected_size = 0 cfi_s = "" cfi = None if len(flash_types) > 0: @@ -1732,7 +1734,37 @@ def AutoDetectFlash(self, limitVoltage=False): size_undetected = True if size_undetected: - if isinstance(cfi, dict) and "device_size" in cfi: + if "flash_bank_select_type" in supp_flash_types[1][flash_types[0]] and supp_flash_types[1][flash_types[0]]["flash_bank_select_type"] == 1: + # Check where the ROM data repeats (by bank switching) + fc_fncptr = { + "cart_write_fncptr":self._cart_write, + "cart_write_fast_fncptr":self._cart_write_flash, + "cart_read_fncptr":self.ReadROM, + "cart_powercycle_fncptr":self.CartPowerCycle, + "progress_fncptr":self.SetProgress, + "set_we_pin_wr":self._set_we_pin_wr, + "set_we_pin_audio":self._set_we_pin_audio, + } + flashcart = Flashcart(config=supp_flash_types[1][flash_types[0]], fncptr=fc_fncptr) + flashcart.SelectBankROM(0) + size_check = self.ReadROM(0, 0x1000) + self.ReadROM(0x1FFF000, 0x1000) + num_banks = 1 + while num_banks < (flashcart.GetFlashSize() // 0x2000000) + 1: + dprint("Checking bank {:d}".format(num_banks)) + flashcart.SelectBankROM(num_banks) + buffer = self.ReadROM(0, 0x1000) + self.ReadROM(0x1FFF000, 0x1000) + if buffer == size_check: break + num_banks <<= 1 + detected_size = 0x2000000 * num_banks + for i in range(0, len(flash_types)): + if detected_size == supp_flash_types[1][flash_types[i]]["flash_size"]: + dprint("Detected {:d} flash banks".format(num_banks)) + flash_type_id = flash_types[i] + size_undetected = False + break + flashcart.SelectBankROM(0) + + elif isinstance(cfi, dict) and "device_size" in cfi: for i in range(0, len(flash_types)): if "flash_size" in supp_flash_types[1][flash_types[i]] and cfi['device_size'] == supp_flash_types[1][flash_types[i]]["flash_size"]: flash_type_id = flash_types[i] @@ -1762,8 +1794,8 @@ def AutoDetectFlash(self, limitVoltage=False): if self.MODE == "DMG" and not flash_id_found: self._write(self.DEVICE_CMD["SET_VOLTAGE_5V"]) time.sleep(0.1) - - return (flash_types, flash_type_id, flash_id, cfi_s, cfi) + + return (flash_types, flash_type_id, flash_id, cfi_s, cfi, detected_size) def CheckFlashChip(self, limitVoltage=False, cart_type=None): # aka. the most horribly written function if cart_type is not None: @@ -2160,7 +2192,7 @@ def _BackupROM(self, args): else: rom_banks = 1 rom_bank_size = 0x2000000 - + is_3dmemory = (self.MODE == "AGB" and "command_set" in cart_type and cart_type["command_set"] == "3DMEMORY") if "verify_write" in args: @@ -2306,7 +2338,7 @@ def _BackupROM(self, args): dprint("Failed to receive 0x{:X} bytes from the device at position 0x{:X}. Decreasing maximum transfer buffer size to 0x{:X}.".format(buffer_len, pos_temp, max_length >> 1)) max_length >>= 1 self.MAX_BUFFER_READ = max_length - err_text += "\nBuffer size adjusted to {:d} bytes...".format(max_length) + err_text += "\nBuffer size adjusted to {:d} bytes.".format(max_length) if ".dev" in Util.VERSION_PEP440 and not Util.DEBUG: print(err_text) self.INFO["dump_info"]["transfer_size"] = max_length @@ -2804,7 +2836,7 @@ def _BackupRestoreRAM(self, args): if agb_flash_chip == 0x1F3D: # Atmel AT29LV512 self.WriteRAM(address=int(pos/128), buffer=buffer[buffer_offset:buffer_offset+buffer_len], command=command) else: - dprint("pos=0x{:X}, sector_address={:d}".format(pos, sector_address)) + dprint("Erasing flash save sector; pos=0x{:X}, sector_address=0x{:X}".format(pos, sector_address)) cmds = [ [ 0x5555, 0xAA ], [ 0x2AAA, 0x55 ], @@ -2823,8 +2855,10 @@ def _BackupRestoreRAM(self, args): if sr == 0xFFFF: break lives -= 1 if lives == 0: - self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Accessing the save data flash chip failed. Please make sure you selected the correct save type. If you are using a reproduction cartridge, check if it really is equipped with a flash chip for save data, or if it uses SRAM for save data instead.", "abortable":False}) - return False + errmsg = "Warning: Save data flash sector at 0x{:X} didn’t erase successfully (SR={:04X}).".format(bank*0x10000 + pos, sr) + print(errmsg) + dprint(errmsg) + break if buffer[buffer_offset:buffer_offset+buffer_len] != bytearray([0xFF] * buffer_len): if ("ereader" in self.INFO and self.INFO["ereader"] is True and sector_address == 0xF000): self.WriteRAM(address=pos, buffer=buffer[buffer_offset:buffer_offset+0xF80], command=command, max_length=0x80) @@ -3393,8 +3427,9 @@ def _FlashROM(self, args): if len(sector_offsets) > 0: flash_capacity = sector_offsets[-1][0] + sector_offsets[-1][1] if flash_capacity < len(data_import) and not (flashcart.SupportsChipErase() and args["prefer_chip_erase"]): - self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"There are not enough flash sectors available to write this ROM. The maximum capacity is {:s}.".format(Util.formatFileSize(size=flash_capacity, asInt=False)), "abortable":False}) - return False + #self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"There are not enough flash sectors available to write this ROM. The maximum capacity is {:s}.".format(Util.formatFileSize(size=flash_capacity, asInt=False)), "abortable":False}) + #return False + sector_offsets = flashcart.GetSectorOffsets(rom_size=len(data_import), rom_bank_size=rom_bank_size) sector_offsets_hash = base64.urlsafe_b64encode(hashlib.sha1(str(sector_offsets).encode("UTF-8")).digest()).decode("ASCII", "ignore")[:4] @@ -3495,7 +3530,7 @@ def _FlashROM(self, args): start_bank = 0 start_address = 0 buffer_pos = 0 - retry_hp = 100 + retry_hp = 0 end_address = len(data_import) dprint("ROM banks:", end_bank) @@ -3503,10 +3538,18 @@ def _FlashROM(self, args): write_sectors = [[ 0, len(data_import) ]] elif write_sectors is None or len(write_sectors) == 0: write_sectors = sector_offsets + + if len(write_sectors) == 0: + self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Coulnd’t start writing ROM because the flash cart couldn’t be detected properly.", "abortable":False}) + return False for sector in write_sectors: if chip_erase is False: - retry_hp = 100 + if retry_hp == 0: + retry_hp = 15 # First sector + else: + retry_hp = 100 # Other sectors + if self.MODE == "AGB": dprint("Writing sector:", hex(sector[0]), hex(sector[1])) buffer_pos = sector[0] @@ -3576,7 +3619,6 @@ def _FlashROM(self, args): flashcart.SelectBankROM(bank) temp = end_address - start_address start_address %= cart_type["flash_bank_size"] - #end_address = start_address + temp end_address = min(cart_type["flash_bank_size"], start_address + temp) # ↑↑↑ Switch ROM bank @@ -3637,22 +3679,42 @@ def _FlashROM(self, args): if status is False or se_ret is False: self.CANCEL = True self.ERROR = True + sr = "Unknown" + if (self.FW["pcb_ver"] in (5, 6) and self.FW["fw_ver"] >= 11): + lives = 3 + while lives > 0: + dprint("Retrieving last status register value...") + self.DEVICE.reset_input_buffer() + self.DEVICE.reset_output_buffer() + self._write(self.DEVICE_CMD["GET_VARIABLE"]) + self._write(2) + self._write(3) + sr = self._read(2) + if sr not in (False, None) and len(sr) == 2: + sr = "0x{:X}".format(struct.unpack(">H", sr)[0]) + break + dprint("Erroneous response:", sr) + lives -= 1 + if lives == 0: + sr = "Timeout" + dprint("Last status register value:", sr) + if "from_user" in self.CANCEL_ARGS and self.CANCEL_ARGS["from_user"]: break - elif buffer_pos == 0 or not self.DEVICE.is_open or self.DEVICE is None: - self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection{:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), errmsg_mbc_selection)}) + elif not self.DEVICE.is_open or self.DEVICE is None: + self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection{:s}\n\nStatus Register: {:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), errmsg_mbc_selection, sr)}) break else: if chip_erase: retry_hp = 0 if "iteration" in self.ERROR_ARGS and self.ERROR_ARGS["iteration"] > 0: retry_hp -= 5 if retry_hp <= 0: - self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"Unstable connection detected while writing 0x{:X} bytes in iteration {:d} at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables".format(buffer_len, self.ERROR_ARGS["iteration"], buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False))}) + self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"Unstable connection detected while writing 0x{:X} bytes in iteration {:d} at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n\nStatus Register: {:s}".format(buffer_len, self.ERROR_ARGS["iteration"], buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), sr)}) continue else: retry_hp -= 10 if retry_hp <= 0: - self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection\n- Check cartridge ROM storage size (at least {:s} is required){:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), Util.formatFileSize(size=len(data_import), asInt=False), errmsg_mbc_selection), "abortable":False}) + self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while writing 0x{:X} bytes at position 0x{:X} ({:s}). Please re-connect the device and try again from the beginning.\n\nTroubleshooting advice:\n- Clean cartridge contacts\n- Avoid passive USB hubs and try different USB ports/cables\n- Check cartridge type selection\n- Check cartridge ROM storage size (at least {:s} is required){:s}\n\nStatus Register: {:s}".format(buffer_len, buffer_pos, Util.formatFileSize(size=buffer_pos, asInt=False), Util.formatFileSize(size=len(data_import), asInt=False), errmsg_mbc_selection, sr), "abortable":False}) continue rev_buffer_pos = sector_offsets[sector_pos - 1][0] @@ -3665,7 +3727,7 @@ def _FlashROM(self, args): pos = end_address status = False - self.SetProgress({"action":"ERROR", "abortable":True, "pos":buffer_pos, "text":"Write error! Retrying from 0x{:X}...".format(rev_buffer_pos)}) + self.SetProgress({"action":"ERROR", "abortable":True, "pos":buffer_pos, "text":err_text}) delay = 0.5 + (100-retry_hp)/50 if self.CanPowerCycleCart(): self.CartPowerOff() diff --git a/FlashGBX/res/config.zip b/FlashGBX/res/config.zip index ca46f93..0f038ab 100644 Binary files a/FlashGBX/res/config.zip and b/FlashGBX/res/config.zip differ diff --git a/FlashGBX/res/fw_GBxCart_RW_v1_3.zip b/FlashGBX/res/fw_GBxCart_RW_v1_3.zip index 018bcf0..22eeef3 100644 Binary files a/FlashGBX/res/fw_GBxCart_RW_v1_3.zip and b/FlashGBX/res/fw_GBxCart_RW_v1_3.zip differ diff --git a/FlashGBX/res/fw_GBxCart_RW_v1_4.zip b/FlashGBX/res/fw_GBxCart_RW_v1_4.zip index 38631b0..d9d12d8 100644 Binary files a/FlashGBX/res/fw_GBxCart_RW_v1_4.zip and b/FlashGBX/res/fw_GBxCart_RW_v1_4.zip differ diff --git a/FlashGBX/res/fw_GBxCart_RW_v1_4a.zip b/FlashGBX/res/fw_GBxCart_RW_v1_4a.zip index bbf6fb4..1a1bce9 100644 Binary files a/FlashGBX/res/fw_GBxCart_RW_v1_4a.zip and b/FlashGBX/res/fw_GBxCart_RW_v1_4a.zip differ diff --git a/README.md b/README.md index 978f9d1..d521ff1 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed - 2006_TSOP_64BALL_QFP48 with AL016J55FFAR2 - 256M29EWH (no PCB text) - 36VF3204 and ALTERA CPLD (no PCB text) + - 512M29EWH (no PCB text) - DMG-DHCN-20 with MX29LV320ET - DMG-GBRW-20 with 29LV320ETMI-70G - DRV with 29LV320DB and ALTERA CPLD @@ -278,6 +279,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed - BX2006_TSOPBGA_6108 with M29W640 - DV15 with MSP55LV100G - F864-3 with M36L0R7050B + - F0095_4G_V1 with F0095H0 - GA-07 with unlabeled flash chip - GE28F128W30 with 128W30B0 - M36XXX_T32_32D_16D with M36L0R806 @@ -323,7 +325,7 @@ Many different reproduction cartridges share their flash chip command set, so ev The author would like to thank the following very kind people for their help, contributions or documentation (in alphabetical order): -2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, bbsan, BennVenn, ccs21, ClassicOldSong, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr +2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, Ausar, bbsan, BennVenn, ccs21, ClassicOldSong, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr ## DISCLAIMER diff --git a/setup.py b/setup.py index b7fdf75..e5fde94 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ setuptools.setup( name="FlashGBX", - version="3.36", + version="3.37", author="Lesserkuma", description="Reads and writes Game Boy and Game Boy Advance cartridge data using the GBxCart RW by insideGadgets", url="https://github.com/lesserkuma/FlashGBX",