mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-04-25 07:57:25 -05:00
3.32
This commit is contained in:
parent
2951fdc7ce
commit
64c4429f14
17
CHANGES.md
17
CHANGES.md
|
|
@ -1,4 +1,21 @@
|
|||
# Release notes
|
||||
### v3.32 (released 2023-07-25)
|
||||
- Added support for M5M29-39VF512 with M5M29HD528 *(thanks marv17)*
|
||||
- Added support for SD007_BV5_V3 with 26LV160BTC
|
||||
- Added support for DL9SEC GBA flashcart with TE28F128 *(thanks olDirdey)*
|
||||
- Added support for DL9SEC GBA flashcart with TE28F256 *(thanks olDirdey)*
|
||||
- Added support for M36XXX_T32_32D_16D with M36L0R8060T *(thanks Merkin)*
|
||||
- Added support for Gamebank-web DMG-29W-04 with M29W320ET *(thanks zipplet)*
|
||||
- Added support for a new bootleg save type based on 1M FLASH
|
||||
- Added support for another flash chip used on the BennVenn MBC3000 RTC cart
|
||||
- Added support for 3680x2 with TH50VSF3680 (only up to 8 MiB) *(thanks kane159)*
|
||||
- Fixed support for BGA64B-71-TV-DEEP with 256M29EML
|
||||
- Confirmed support for FunnyPlaying MidnightTrace 4 MiB Game Boy Flash Cart *(thanks AlexiG)*
|
||||
- Confirmed support for FunnyPlaying MidnightTrace 32 MiB Game Boy Advance Flash Cart *(thanks AlexiG)*
|
||||
- Confirmed support for 2006-36-71_V2 with M36L0R8060B *(thanks kane159)*
|
||||
- Updated the Game Boy Advance lookup databases for save types, ROM sizes and checksums
|
||||
- Minor bug fixes and improvements *(thanks Falknör, Crystal)*
|
||||
|
||||
### v3.31 (released 2023-06-18)
|
||||
- Improved support for 32 MiB cartridges that have one of the EEPROM save types (fixes both backups and writes of B3CJ, B53E, B53P, BBAE, BBAP, BC2J, BFRP, BH3E, BH3P, BH8E, BJPP, BU7E, BU7P, BX3E, BX3P, BYUE, BYUJ, BYUP)
|
||||
- Confirmed support for BGA64B-71-TV-DEEP with 256M29EML *(thanks Leitplanke)*
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ class FlashGBX_CLI():
|
|||
print("\n{:s}Couldn’t read cartridge header. Please try again.{:s}\n".format(ANSI.RED, ANSI.RESET))
|
||||
self.DisconnectDevice()
|
||||
return
|
||||
elif bad_read and not args.ignore_bad_header and ("mapper_raw" in header and header["mapper_raw"] != 0x203):
|
||||
if bad_read and not args.ignore_bad_header and (self.CONN.GetMode() == "AGB" or (self.CONN.GetMode() == "DMG" and "mapper_raw" in header and header["mapper_raw"] != 0x203)):
|
||||
print("\n{:s}Invalid data was detected which usually means that the cartridge couldn’t be read correctly. Please make sure you selected the correct mode and that the cartridge contacts are clean. This check can be disabled with the command line switch “--ignore-bad-header”.{:s}\n".format(ANSI.RED, ANSI.RESET))
|
||||
print("Cartridge Information:")
|
||||
print(s_header)
|
||||
|
|
@ -462,6 +462,9 @@ class FlashGBX_CLI():
|
|||
|
||||
if data["logo_correct"]:
|
||||
s += "Nintendo Logo: OK\n"
|
||||
if not os.path.exists(Util.CONFIG_PATH + "/bootlogo_dmg.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_dmg.bin", "wb") as f:
|
||||
f.write(data['raw'][0x104:0x134])
|
||||
else:
|
||||
s += "Nintendo Logo: {:s}Invalid{:s}\n".format(ANSI.RED, ANSI.RESET)
|
||||
bad_read = True
|
||||
|
|
@ -517,6 +520,9 @@ class FlashGBX_CLI():
|
|||
|
||||
if data["logo_correct"]:
|
||||
s += "Nintendo Logo: OK\n"
|
||||
if not os.path.exists(Util.CONFIG_PATH + "/bootlogo_agb.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_agb.bin", "wb") as f:
|
||||
f.write(data['raw'][0x04:0xA0])
|
||||
else:
|
||||
s += "Nintendo Logo: {:s}Invalid{:s}\n".format(ANSI.RED, ANSI.RESET)
|
||||
bad_read = True
|
||||
|
|
@ -895,6 +901,7 @@ class FlashGBX_CLI():
|
|||
|
||||
verify_write = args.no_verify_write is False
|
||||
|
||||
fix_bootlogo = False
|
||||
fix_header = False
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
hdr = RomFileDMG(buffer).GetHeader()
|
||||
|
|
@ -938,7 +945,24 @@ class FlashGBX_CLI():
|
|||
elif self.CONN.GetMode() == "AGB":
|
||||
hdr = RomFileAGB(buffer).GetHeader()
|
||||
if not hdr["logo_correct"] and (self.CONN.GetMode() == "AGB" or (self.CONN.GetMode() == "DMG" and mbc not in (0x203, 0x205))):
|
||||
print("{:s}WARNING: The ROM file you selected will not boot on actual hardware due to invalid logo data.{:s}".format(ANSI.YELLOW, ANSI.RESET))
|
||||
print("{:s}Warning: The ROM file you selected will not boot on actual hardware due to invalid boot logo data.{:s}".format(ANSI.YELLOW, ANSI.RESET))
|
||||
bootlogo = None
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
if os.path.exists(Util.CONFIG_PATH + "/bootlogo_dmg.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_dmg.bin", "rb") as f:
|
||||
bootlogo = bytearray(f.read(0x30))
|
||||
elif self.CONN.GetMode() == "AGB":
|
||||
if os.path.exists(Util.CONFIG_PATH + "/bootlogo_agb.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_agb.bin", "rb") as f:
|
||||
bootlogo = bytearray(f.read(0x9C))
|
||||
if bootlogo is not None:
|
||||
answer = input("Fix the boot logo before continuing? [Y/n]: ").strip().lower()
|
||||
print("")
|
||||
if answer != "n":
|
||||
fix_bootlogo = bootlogo
|
||||
else:
|
||||
Util.dprint("Couldn’t find boot logo file in configuration directory.")
|
||||
|
||||
if not hdr["header_checksum_correct"] and (self.CONN.GetMode() == "AGB" or (self.CONN.GetMode() == "DMG" and mbc not in (0x203, 0x205))):
|
||||
print("{:s}WARNING: The ROM file you selected will not boot on actual hardware due to an invalid header checksum (expected 0x{:02X} instead of 0x{:02X}).{:s}".format(ANSI.YELLOW, hdr["header_checksum_calc"], hdr["header_checksum"], ANSI.RESET))
|
||||
answer = input("Fix the header checksum before continuing? [Y/n]: ").strip().lower()
|
||||
|
|
@ -953,9 +977,9 @@ class FlashGBX_CLI():
|
|||
|
||||
print("")
|
||||
if len(buffer) > 0x1000:
|
||||
args = { "mode":4, "path":"", "buffer":buffer, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "mbc":mbc }
|
||||
args = { "mode":4, "path":"", "buffer":buffer, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "fix_bootlogo":fix_bootlogo, "mbc":mbc }
|
||||
else:
|
||||
args = { "mode":4, "path":path, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "mbc":mbc }
|
||||
args = { "mode":4, "path":path, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "fix_bootlogo":fix_bootlogo, "mbc":mbc }
|
||||
self.CONN.TransferData(signal=self.PROGRESS.SetProgress, args=args)
|
||||
|
||||
buffer = None
|
||||
|
|
|
|||
|
|
@ -922,7 +922,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
msgbox.exec()
|
||||
else:
|
||||
self.lblStatus4a.setText("Done.")
|
||||
#if ("cart_type" in self.STATUS and "dmg-mmsa-jpn" in self.STATUS["cart_type"]) or ("mapper_raw" in self.CONN.INFO and self.CONN.INFO["mapper_raw"] in (0x105, 0x202, 0x203, 0x205)):
|
||||
if "mapper_raw" in self.CONN.INFO and self.CONN.INFO["mapper_raw"] in (0x202, 0x203, 0x205):
|
||||
msg = "The ROM backup is complete."
|
||||
msgbox.setText(msg + msg_te)
|
||||
|
|
@ -1306,6 +1305,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
else:
|
||||
verify_write = False
|
||||
|
||||
fix_bootlogo = False
|
||||
fix_header = False
|
||||
if not just_erase and len(buffer) >= 0x1000:
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
|
|
@ -1341,8 +1341,42 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
hdr = RomFileAGB(buffer).GetHeader()
|
||||
|
||||
if not hdr["logo_correct"] and (self.CONN.GetMode() == "AGB" or (self.CONN.GetMode() == "DMG" and mbc not in (0x203, 0x205))):
|
||||
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), "Warning: The ROM file you selected will not boot on actual hardware due to invalid boot logo data.", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||
if answer == QtWidgets.QMessageBox.Cancel: return
|
||||
msg_text = "Warning: The ROM file you selected will not boot on actual hardware due to invalid boot logo data."
|
||||
bootlogo = None
|
||||
if self.CONN.GetMode() == "DMG":
|
||||
if os.path.exists(Util.CONFIG_PATH + "/bootlogo_dmg.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_dmg.bin", "rb") as f:
|
||||
bootlogo = bytearray(f.read(0x30))
|
||||
elif self.CONN.GetMode() == "AGB":
|
||||
if os.path.exists(Util.CONFIG_PATH + "/bootlogo_agb.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_agb.bin", "rb") as f:
|
||||
bootlogo = bytearray(f.read(0x9C))
|
||||
if bootlogo is not None:
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg_text)
|
||||
button_1 = msgbox.addButton(" &Fix and Continue ", QtWidgets.QMessageBox.ActionRole)
|
||||
button_2 = msgbox.addButton(" Continue &without fixing ", QtWidgets.QMessageBox.ActionRole)
|
||||
button_cancel = msgbox.addButton("&Cancel", QtWidgets.QMessageBox.RejectRole)
|
||||
msgbox.setDefaultButton(button_1)
|
||||
msgbox.setEscapeButton(button_cancel)
|
||||
msgbox.exec()
|
||||
if msgbox.clickedButton() == button_1:
|
||||
fix_bootlogo = bootlogo
|
||||
elif msgbox.clickedButton() == button_cancel:
|
||||
return
|
||||
elif msgbox.clickedButton() == button_2:
|
||||
pass
|
||||
else:
|
||||
Util.dprint("Couldn’t find boot logo file in configuration directory.")
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg_text)
|
||||
msgbox.setStandardButtons(QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel)
|
||||
msgbox.setDefaultButton(QtWidgets.QMessageBox.Cancel)
|
||||
msgbox.setEscapeButton(QtWidgets.QMessageBox.Cancel)
|
||||
retval = msgbox.exec()
|
||||
if retval == QtWidgets.QMessageBox.Cancel:
|
||||
return
|
||||
else:
|
||||
pass
|
||||
|
||||
if not hdr["header_checksum_correct"] and (self.CONN.GetMode() == "AGB" or (self.CONN.GetMode() == "DMG" and mbc not in (0x203, 0x205))):
|
||||
msg_text = "Warning: The ROM file you selected will not boot on actual hardware due to an invalid header checksum (expected 0x{:02X} instead of 0x{:02X}).".format(hdr["header_checksum_calc"], hdr["header_checksum"])
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Warning, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg_text)
|
||||
|
|
@ -1372,9 +1406,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if just_erase:
|
||||
prefer_chip_erase = True
|
||||
verify_write = False
|
||||
args = { "path":"", "buffer":buffer, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "mbc":mbc }
|
||||
args = { "path":"", "buffer":buffer, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "fix_bootlogo":fix_bootlogo, "mbc":mbc }
|
||||
else:
|
||||
args = { "path":path, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "mbc":mbc, "flash_offset":flash_offset }
|
||||
args = { "path":path, "cart_type":cart_type, "override_voltage":override_voltage, "prefer_chip_erase":prefer_chip_erase, "fast_read_mode":True, "verify_write":verify_write, "fix_header":fix_header, "fix_bootlogo":fix_bootlogo, "mbc":mbc, "flash_offset":flash_offset }
|
||||
self.CONN.FlashROM(fncSetProgress=self.PROGRESS.SetProgress, args=args)
|
||||
#self.CONN._FlashROM(args=args)
|
||||
self.grpStatus.setTitle("Transfer Status")
|
||||
|
|
@ -1828,7 +1862,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
bl_args = self.GetBLArgs(rom_size=Util.AGB_Header_ROM_Sizes_Map[self.cmbAGBHeaderROMSizeResult.currentIndex()], detected=detected)
|
||||
if bl_args is False: return
|
||||
|
||||
args = { "path":path, "cart_type":cart_type, "override_voltage":False, "prefer_chip_erase":False, "fast_read_mode":True, "verify_write":verify_write, "fix_header":False, "mbc":mbc }
|
||||
args = { "path":path, "cart_type":cart_type, "override_voltage":False, "prefer_chip_erase":False, "fast_read_mode":True, "verify_write":verify_write, "fix_header":False, "fix_bootlogo":False, "mbc":mbc }
|
||||
args.update({"bl_save":True, "flash_offset":bl_args["bl_offset"], "flash_size":bl_args["bl_size"]})
|
||||
if erase:
|
||||
args["path"] = ""
|
||||
|
|
@ -2096,6 +2130,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if data['logo_correct'] and data['header_checksum_correct']:
|
||||
self.lblDMGHeaderBootlogoResult.setText("OK")
|
||||
self.lblDMGHeaderBootlogoResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
||||
if not os.path.exists(Util.CONFIG_PATH + "/bootlogo_dmg.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_dmg.bin", "wb") as f:
|
||||
f.write(data['raw'][0x104:0x134])
|
||||
else:
|
||||
self.lblDMGHeaderBootlogoResult.setText("Invalid")
|
||||
self.lblDMGHeaderBootlogoResult.setStyleSheet("QLabel { color: red; }")
|
||||
|
|
@ -2136,7 +2173,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.lblDMGHeaderBootlogoResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
||||
self.lblDMGHeaderROMChecksumResult.setText("")
|
||||
self.lblDMGHeaderROMChecksumResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
||||
elif data["mapper_raw"] == 0x205: # Datel Orbit V2
|
||||
elif data["mapper_raw"] == 0x205: # Datel
|
||||
self.lblDMGHeaderRtcResult.setText("")
|
||||
self.lblDMGHeaderBootlogoResult.setText("")
|
||||
self.lblDMGHeaderBootlogoResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
||||
|
|
@ -2153,14 +2190,20 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.lblDMGHeaderBootlogoResult.setStyleSheet(self.lblDMGRomTitleResult.styleSheet())
|
||||
if "logo_sachen" in data:
|
||||
data["logo_sachen"].putpalette([ 255, 255, 255, 128, 128, 128 ])
|
||||
self.lblDMGHeaderBootlogoResult.setPixmap(QtGui.QPixmap.fromImage(ImageQt(data["logo_sachen"].convert("RGBA"))))
|
||||
try:
|
||||
self.lblDMGHeaderBootlogoResult.setPixmap(QtGui.QPixmap.fromImage(ImageQt(data["logo_sachen"].convert("RGBA"))))
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if "logo" in data:
|
||||
if data['logo_correct']:
|
||||
data["logo"].putpalette([ 255, 255, 255, self.TEXT_COLOR[0], self.TEXT_COLOR[1], self.TEXT_COLOR[2] ])
|
||||
else:
|
||||
data["logo"].putpalette([ 255, 255, 255, 251, 0, 24 ])
|
||||
self.lblDMGHeaderBootlogoResult.setPixmap(QtGui.QPixmap.fromImage(ImageQt(data["logo"].convert("RGBA"))))
|
||||
try:
|
||||
self.lblDMGHeaderBootlogoResult.setPixmap(QtGui.QPixmap.fromImage(ImageQt(data["logo"].convert("RGBA"))))
|
||||
except:
|
||||
pass
|
||||
|
||||
self.grpAGBCartridgeInfo.setVisible(False)
|
||||
self.grpDMGCartridgeInfo.setVisible(True)
|
||||
|
|
@ -2194,6 +2237,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
if data['logo_correct']:
|
||||
self.lblAGBHeaderLogoValidResult.setText("OK")
|
||||
self.lblAGBHeaderLogoValidResult.setStyleSheet(self.lblAGBRomTitleResult.styleSheet())
|
||||
if not os.path.exists(Util.CONFIG_PATH + "/bootlogo_agb.bin"):
|
||||
with open(Util.CONFIG_PATH + "/bootlogo_agb.bin", "wb") as f:
|
||||
f.write(data['raw'][0x04:0xA0])
|
||||
else:
|
||||
self.lblAGBHeaderLogoValidResult.setText("Invalid")
|
||||
self.lblAGBHeaderLogoValidResult.setStyleSheet("QLabel { color: red; }")
|
||||
|
|
@ -2619,18 +2665,23 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
speed = 0
|
||||
elapsed = 0
|
||||
left = 0
|
||||
estimated = 0
|
||||
if "pos" in args: pos = args["pos"]
|
||||
if "size" in args: size = args["size"]
|
||||
if "speed" in args: speed = args["speed"]
|
||||
if "time_elapsed" in args: elapsed = args["time_elapsed"]
|
||||
if "time_left" in args: left = args["time_left"]
|
||||
if "time_estimated" in args: estimated = args["time_estimated"]
|
||||
|
||||
if "action" in args:
|
||||
if args["action"] == "ERASE":
|
||||
self.lblStatus1aResult.setText("Pending...")
|
||||
self.lblStatus2aResult.setText("Pending...")
|
||||
self.lblStatus3aResult.setText(Util.formatProgressTime(elapsed))
|
||||
self.lblStatus4a.setText("Erasing flash... This may take some time.")
|
||||
if estimated != 0:
|
||||
self.lblStatus4a.setText("Erasing... This may take up to {:d} seconds.".format(estimated))
|
||||
else:
|
||||
self.lblStatus4a.setText("Erasing... This may take some time.")
|
||||
self.lblStatus4aResult.setText("")
|
||||
self.btnCancel.setEnabled(args["abortable"])
|
||||
self.SetProgressBars(min=0, max=size, value=pos)
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ class Flashcart:
|
|||
def ChipErase(self):
|
||||
self.Reset(full_reset=True)
|
||||
time_start = time.time()
|
||||
if self.PROGRESS_FNCPTR is not None: self.PROGRESS_FNCPTR({"action":"ERASE", "time_start":time_start, "abortable":False})
|
||||
if self.PROGRESS_FNCPTR is not None: self.PROGRESS_FNCPTR({"action":"ERASE", "time_start":time_start, "time_estimated": self.CONFIG["chip_erase_timeout"], "abortable":False})
|
||||
for i in range(0, len(self.CONFIG["commands"]["chip_erase"])):
|
||||
addr = self.CONFIG["commands"]["chip_erase"][i][0]
|
||||
data = self.CONFIG["commands"]["chip_erase"][i][1]
|
||||
|
|
@ -331,10 +331,9 @@ class Flashcart:
|
|||
data = self.CONFIG["commands"]["chip_erase_wait_for"][i][1]
|
||||
timeout = self.CONFIG["chip_erase_timeout"]
|
||||
while True:
|
||||
if self.PROGRESS_FNCPTR is not None: self.PROGRESS_FNCPTR({"action":"ERASE", "time_start":time_start, "abortable":False})
|
||||
if self.PROGRESS_FNCPTR is not None: self.PROGRESS_FNCPTR({"action":"ERASE", "time_start":time_start, "time_estimated": self.CONFIG["chip_erase_timeout"], "abortable":False})
|
||||
if "wait_read_status_register" in self.CONFIG and self.CONFIG["wait_read_status_register"]:
|
||||
for j in range(0, len(self.CONFIG["commands"]["read_status_register"])):
|
||||
#sr_addr = self.CONFIG["commands"]["read_status_register"][j][0]
|
||||
sr_data = self.CONFIG["commands"]["read_status_register"][j][1]
|
||||
|
||||
if we == "WR":
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ class GBMemoryMap:
|
|||
info["ram_start_block"] = int(ram_offset / 0x800)
|
||||
ram_offset += info["ram_data_size"]
|
||||
info["rom_header"] = RomFileDMG(data[info["rom_data_offset"]:info["rom_data_offset"]+0x180]).GetHeader()
|
||||
if len(info["rom_header"]) == 0: return
|
||||
mbc_type = self.MapperToMBCType(info["rom_header"]["mapper_raw"])
|
||||
if mbc_type is False: return
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ class DMG_MBC:
|
|||
return DMG_Unlicensed_Sachen(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
|
||||
elif mbc_id == 0x205: # 0x205:'Datel Orbit V2',
|
||||
return DMG_Unlicensed_DatelOrbitV2(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
|
||||
# elif mbc_id == 0x206: # 0x206:'Datel MegaMem',
|
||||
# return DMG_Unlicensed_DatelMegaMem(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
|
||||
else:
|
||||
self.__init__(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
|
||||
return self
|
||||
|
|
@ -667,6 +669,17 @@ class DMG_GBD(DMG_MBC5):
|
|||
def GetName(self):
|
||||
return "MAC-GBD"
|
||||
|
||||
def SelectBankROM(self, index):
|
||||
dprint(self.GetName(), "|", index)
|
||||
commands = [
|
||||
[ 0x2100, index & 0xFF ],
|
||||
]
|
||||
|
||||
start_address = 0 if index == 0 else 0x4000
|
||||
|
||||
self.CartWrite(commands)
|
||||
return (start_address, self.ROM_BANK_SIZE)
|
||||
|
||||
def GetMaxROMSize(self):
|
||||
return 1*1024*1024
|
||||
|
||||
|
|
@ -830,6 +843,17 @@ class DMG_HuC1(DMG_MBC5):
|
|||
def GetName(self):
|
||||
return "HuC-1"
|
||||
|
||||
def SelectBankROM(self, index):
|
||||
dprint(self.GetName(), "|", index)
|
||||
commands = [
|
||||
[ 0x2100, index & 0xFF ],
|
||||
]
|
||||
|
||||
start_address = 0 if index == 0 else 0x4000
|
||||
|
||||
self.CartWrite(commands)
|
||||
return (start_address, self.ROM_BANK_SIZE)
|
||||
|
||||
def EnableRAM(self, enable=True):
|
||||
dprint(self.GetName(), "|", enable)
|
||||
commands = [
|
||||
|
|
@ -1412,6 +1436,31 @@ class DMG_Unlicensed_DatelOrbitV2(DMG_MBC):
|
|||
def GetMaxROMSize(self):
|
||||
return 128*1024
|
||||
|
||||
# class DMG_Unlicensed_DatelMegaMem(DMG_MBC):
|
||||
# def GetName(self):
|
||||
# return "Datel MegaMem"
|
||||
|
||||
# def __init__(self, args=None, cart_write_fncptr=None, cart_read_fncptr=None, cart_powercycle_fncptr=None, clk_toggle_fncptr=None):
|
||||
# if args is None: args = {}
|
||||
# super().__init__(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, cart_powercycle_fncptr=cart_powercycle_fncptr, clk_toggle_fncptr=None)
|
||||
# self.ROM_BANK_SIZE = 0x4000
|
||||
# self.RAM_BANK_SIZE = 0x4000
|
||||
|
||||
# def SelectBankROM(self, index):
|
||||
# dprint(self.GetName(), "|", index)
|
||||
# return (0, self.ROM_BANK_SIZE)
|
||||
|
||||
# def SelectBankRAM(self, index):
|
||||
# dprint(self.GetName(), "|", index)
|
||||
# self.CartWrite([[ 0x2000, index & 0x20 ]])
|
||||
# return (0x4000, self.RAM_BANK_SIZE)
|
||||
|
||||
# def GetROMBanks(self, rom_size):
|
||||
# return 1
|
||||
|
||||
# def GetMaxROMSize(self):
|
||||
# return 16*1024
|
||||
|
||||
|
||||
class AGB_GPIO:
|
||||
CART_WRITE_FNCPTR = None
|
||||
|
|
@ -1590,8 +1639,7 @@ class AGB_GPIO:
|
|||
buffer.append(self.RTCReadStatus()) # 24h mode = 0x40, reset flag = 0x80
|
||||
buffer.extend(struct.pack("<Q", ts))
|
||||
|
||||
dstr = ' '.join(format(x, '02X') for x in buffer)
|
||||
dprint("[{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))
|
||||
dprint(' '.join(format(x, '02X') for x in buffer))
|
||||
|
||||
# Digits are BCD (Binary Coded Decimal)
|
||||
#[07] 00 01 27 05 06 30 20
|
||||
|
|
@ -1703,6 +1751,6 @@ class AGB_GPIO:
|
|||
rtc_s = (rtc_buffer[6] & 0x0F) + ((rtc_buffer[6] >> 4) * 10)
|
||||
|
||||
if rtc_y == 0 and rtc_m == 0 and rtc_d == 0 and rtc_h == 0 and rtc_i == 0 and rtc_s == 0:
|
||||
return "Not available"
|
||||
raise Exception("Invalid RTC data")
|
||||
else:
|
||||
return "20{:02d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(rtc_y, rtc_m, rtc_d, rtc_h, rtc_i, rtc_s)
|
||||
|
|
|
|||
|
|
@ -251,11 +251,13 @@ class RomFileDMG:
|
|||
pass
|
||||
|
||||
# Unlicensed Datel Orbit V2 Mapper (older firmware)
|
||||
elif hashlib.sha1(buffer[0x101:0x140]).digest() == bytearray([ 0xC1, 0xF4, 0x15, 0x4A, 0xEF, 0xCC, 0x5B, 0xE7, 0xEC, 0x83, 0xA8, 0xBB, 0x7B, 0xC0, 0x95, 0x83, 0x35, 0xEC, 0x9A, 0xF2 ]):
|
||||
elif (
|
||||
hashlib.sha1(buffer[0x101:0x140]).digest() == bytearray([ 0xC1, 0xF4, 0x15, 0x4A, 0xEF, 0xCC, 0x5B, 0xE7, 0xEC, 0x83, 0xA8, 0xBB, 0x7B, 0xC0, 0x95, 0x83, 0x35, 0xEC, 0x9A, 0xF2 ]) or \
|
||||
hashlib.sha1(buffer[0x101:0x140]).digest() == bytearray([ 0xC9, 0x50, 0x65, 0xCB, 0x31, 0x96, 0x26, 0x6C, 0x32, 0x58, 0xAB, 0x07, 0xA1, 0x9E, 0x0C, 0x10, 0xA6, 0xED, 0xCC, 0x67 ])
|
||||
):
|
||||
data["rom_size_raw"] = 0x02
|
||||
data["ram_size_raw"] = 0
|
||||
data["mapper_raw"] = 0x205
|
||||
data["cgb"] = 0x80
|
||||
try:
|
||||
game_title = bytearray(buffer[0x134:0x140]).decode("ascii", "replace").replace("\xFF", "")
|
||||
game_title = re.sub(r"(\x00+)$", "", game_title)
|
||||
|
|
@ -264,7 +266,21 @@ class RomFileDMG:
|
|||
data["game_title"] = game_title
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
# Unlicensed Datel Mega Memory Card
|
||||
# elif hashlib.sha1(buffer[0x104:0x150]).digest() == bytearray([ 0x05, 0xBE, 0x44, 0xBA, 0xE8, 0x0A, 0x59, 0x76, 0x34, 0x1B, 0x01, 0xDF, 0x92, 0xDD, 0xAB, 0x8C, 0x7A, 0x2A, 0x8F, 0x4E ]):
|
||||
# data["rom_size_raw"] = 0x00
|
||||
# data["ram_size_raw"] = 0x206
|
||||
# data["mapper_raw"] = 0x206
|
||||
# try:
|
||||
# game_title = bytearray(buffer[0:0x10]).decode("ascii", "replace").replace("\xFF", "")
|
||||
# game_title = re.sub(r"(\x00+)$", "", game_title)
|
||||
# game_title = re.sub(r"((_)_+|(\x00)\x00+|(\s)\s+)", "\\2\\3\\4", game_title).replace("\x00", "")
|
||||
# game_title = ''.join(filter(lambda x: x in set(string.printable), game_title))
|
||||
# data["game_title"] = game_title
|
||||
# except:
|
||||
# pass
|
||||
|
||||
# Unlicensed Sachen MMC1/MMC2
|
||||
elif len(buffer) >= 0x280:
|
||||
sachen_version = 0
|
||||
|
|
|
|||
|
|
@ -7,9 +7,9 @@ from enum import Enum
|
|||
|
||||
# Common constants
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "3.31"
|
||||
VERSION_PEP440 = "3.32"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
VERSION_TIMESTAMP = 1687091551
|
||||
VERSION_TIMESTAMP = 1690298775
|
||||
DEBUG = False
|
||||
DEBUG_LOG = []
|
||||
APP_PATH = ""
|
||||
|
|
@ -19,8 +19,8 @@ AGB_Header_ROM_Sizes = [ "64 KiB", "128 KiB", "256 KiB", "512 KiB", "1 MiB", "2
|
|||
AGB_Header_ROM_Sizes_Map = [ 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000 ]
|
||||
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" }
|
||||
AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 0x20000, 0x20000 ]
|
||||
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" }
|
||||
AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 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' }
|
||||
DMG_Mapper_Types = { "None":[ 0x00, 0x08, 0x09 ], "MBC1":[ 0x01, 0x02, 0x03 ], "MBC2":[ 0x05, 0x06 ], "MBC3":[ 0x0F, 0x10, 0x11, 0x12, 0x13 ], "MBC30":[ 0x110 ], "MBC5":[ 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E ], "MBC6":[ 0x20 ], "MBC7":[ 0x22 ], "MBC1M":[ 0x101, 0x103 ], "MMM01":[ 0x0B, 0x0D ], "MAC-GBD":[ 0xFC ], "G-MMC1":[ 0x105 ], "M161":[ 0x104 ], "HuC-1":[ 0xFF ], "HuC-3":[ 0xFE ], "TAMA5":[ 0xFD ], "Unlicensed 256M Multi Cart Mapper":[ 0x201 ], "Unlicensed Wisdom Tree Mapper":[ 0x202 ], "Unlicensed Xploder GB Mapper":[ 0x203 ], "Unlicensed Sachen Mapper":[ 0x204 ], "Unlicensed Datel Orbit V2 Mapper":[ 0x205 ] }
|
||||
|
|
@ -29,7 +29,7 @@ DMG_Header_ROM_Sizes_Map = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x0
|
|||
DMG_Header_ROM_Sizes_Flasher_Map = [ 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000 ]
|
||||
DMG_Header_RAM_Sizes = [ "None", "4K SRAM (512 Bytes)", "16K SRAM (2 KiB)", "64K SRAM (8 KiB)", "256K SRAM (32 KiB)", "512K SRAM (64 KiB)", "1M SRAM (128 KiB)", "MBC6 SRAM+FLASH (1.03 MiB)", "MBC7 2K EEPROM (256 Bytes)", "MBC7 4K EEPROM (512 Bytes)", "TAMA5 EEPROM (32 Bytes)", "Unlicensed 4M SRAM (512 KiB)", "Unlicensed 1M EEPROM (128 KiB)" ]
|
||||
DMG_Header_RAM_Sizes_Map = [ 0x00, 0x100, 0x01, 0x02, 0x03, 0x05, 0x04, 0x104, 0x101, 0x102, 0x103, 0x201, 0x203, 0x204 ]
|
||||
DMG_Header_RAM_Sizes_Flasher_Map = [ 0, 0x200, 0x800, 0x2000, 0x8000, 0x10000, 0x20000, 0x108000, 0x100, 0x200, 0x20, 0x80000, 0x20000 ] # RAM size in bytes
|
||||
DMG_Header_RAM_Sizes_Flasher_Map = [ 0, 0x200, 0x800, 0x2000, 0x8000, 0x10000, 0x20000, 0x108000, 0x100, 0x200, 0x20, 0x80000, 0x20000, 0x80000 ] # RAM size in bytes
|
||||
DMG_Header_SGB = { 0x00:'No support', 0x03:'Supported' }
|
||||
DMG_Header_CGB = { 0x00:'No support', 0x80:'Supported', 0xC0:'Required' }
|
||||
|
||||
|
|
|
|||
|
|
@ -3080,7 +3080,7 @@
|
|||
"rg": "Japan"
|
||||
},
|
||||
"c5273c7680baf28bf8f67cd02656c21c698dec58": {
|
||||
"gn": "Aero the Acro-Bat - Rascal Rival Revenge",
|
||||
"gn": "Aero the Acro-Bat",
|
||||
"ne": "(USA)",
|
||||
"gc": "AAOE",
|
||||
"rc": 3027943456,
|
||||
|
|
@ -3102,7 +3102,7 @@
|
|||
"rg": "Japan"
|
||||
},
|
||||
"b071b79502414d994dfdc504668bbc3aecfb6cb7": {
|
||||
"gn": "Aero the Acro-Bat - Rascal Rival Revenge",
|
||||
"gn": "Aero the Acro-Bat",
|
||||
"ne": "(Europe)",
|
||||
"gc": "AAOP",
|
||||
"rc": 2817101502,
|
||||
|
|
@ -21771,8 +21771,8 @@
|
|||
"gc": "BGYJ",
|
||||
"rc": 4094564777,
|
||||
"rs": 16777216,
|
||||
"st": 0,
|
||||
"ss": 0,
|
||||
"st": 1,
|
||||
"ss": 512,
|
||||
"rv": "Rev 1",
|
||||
"lg": "Ja",
|
||||
"rg": "Japan"
|
||||
|
|
@ -23172,8 +23172,8 @@
|
|||
"gc": "BJGE",
|
||||
"rc": 1848475391,
|
||||
"rs": 16777216,
|
||||
"st": 0,
|
||||
"ss": 0,
|
||||
"st": 2,
|
||||
"ss": 8192,
|
||||
"lg": "En",
|
||||
"rg": "Australia"
|
||||
},
|
||||
|
|
@ -31489,7 +31489,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA, Europe",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"dd992df47247919cbb252015b4ff093e3156d320": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Limited Edition",
|
||||
|
|
@ -31501,7 +31501,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"54a6e77c02eae428b8b438035ba8215d621dc54f": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Platinum Edition",
|
||||
|
|
@ -31513,7 +31513,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA, Europe",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"73f8adcdf1fb2766c13ab65c0470af2b23801a7a": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Edition Platinum",
|
||||
|
|
@ -31525,7 +31525,7 @@
|
|||
"ss": 0,
|
||||
"lg": "Fr",
|
||||
"rg": "France",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"e6976665b9e9979e270c95230fbbd08350f09f99": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Premium Edition",
|
||||
|
|
@ -31537,7 +31537,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA, Europe",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"772d68fe78dc92febbb12b6c1172d26c68031706": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Edition Premium",
|
||||
|
|
@ -31549,7 +31549,7 @@
|
|||
"ss": 0,
|
||||
"lg": "Fr",
|
||||
"rg": "France",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"790103a28c22bfcfa52de31f9a1061b17708dc3c": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Special Edition",
|
||||
|
|
@ -31574,7 +31574,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA, Europe",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"a9861107e3c0eadf7a2c6fbf970155cb059f869e": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Edition Speciale",
|
||||
|
|
@ -31586,7 +31586,7 @@
|
|||
"ss": 0,
|
||||
"lg": "Fr",
|
||||
"rg": "France",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"590318cf40cad4d866dd385b6b208a99c6eeec62": {
|
||||
"gn": "Game Boy Advance Video - Cartoon Network Collection - Volume 1",
|
||||
|
|
@ -31610,7 +31610,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"28c8afa6b5d0d24d2c540413e948d4c9c7c44e63": {
|
||||
"gn": "Game Boy Advance Video - Disney Channel Collection - Volume 1",
|
||||
|
|
@ -31622,7 +31622,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"bfe44e65a6ca22ed091c82b475999a4818f60b83": {
|
||||
"gn": "Game Boy Advance Video - Dora the Explorer - Volume 1",
|
||||
|
|
@ -31684,7 +31684,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"0c411aef0ac6be4e8e9ae9b9e8d259cae942b8b1": {
|
||||
"gn": "Game Boy Advance Video - All Grown Up! - Volume 1",
|
||||
|
|
@ -31732,7 +31732,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"1fc3d70d3f225dfdad2dfb70d8336368d4aa8982": {
|
||||
"gn": "Game Boy Advance Video - Nicktoons - Volume 3",
|
||||
|
|
@ -31744,7 +31744,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"49e8ad4da336076f9b0dc8c885e36f7192701fc9": {
|
||||
"gn": "Game Boy Advance Video - Nicktoons Collection - Volume 1",
|
||||
|
|
@ -31829,7 +31829,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"41b14883cc3e05653a7f039944b11a1223f4cf66": {
|
||||
"gn": "Game Boy Advance Video - Shark Tale",
|
||||
|
|
@ -31917,7 +31917,7 @@
|
|||
"ss": 0,
|
||||
"lg": "En",
|
||||
"rg": "USA",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"99bf48542a03e1bceb2a9a82da7257874ec30670": {
|
||||
"gn": "Game Boy Advance Video - SpongeBob SquarePants - Volume 1",
|
||||
|
|
@ -31967,7 +31967,7 @@
|
|||
"ss": 0,
|
||||
"lg": "Fr",
|
||||
"rg": "France",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"dc0c4e5a4c2cdcbbf86e2a16ca9e2060fea6e943": {
|
||||
"gn": "Game Boy Advance Video - Yu-Gi-Oh! - Yugi vs. Joey",
|
||||
|
|
@ -31991,7 +31991,7 @@
|
|||
"ss": 0,
|
||||
"lg": "Fr",
|
||||
"rg": "France",
|
||||
"3d": true
|
||||
"3d": false
|
||||
},
|
||||
"10b3242f409611c32749f9b42f7c7ea951c5fc6d": {
|
||||
"gn": "Card e-Reader",
|
||||
|
|
|
|||
|
|
@ -1,31 +1,4 @@
|
|||
{
|
||||
"523920f7199a60b49357ba21c4abec6b9a3c9734": {
|
||||
"gn": "2097 ROM Pack II",
|
||||
"ne": "(USA) (Test Program)",
|
||||
"gc": "",
|
||||
"rc": 177911527,
|
||||
"rs": 32768,
|
||||
"lg": "En",
|
||||
"rg": "USA"
|
||||
},
|
||||
"539cbc25e424e40a31a01160fcb47fa3487b1654": {
|
||||
"gn": "2420 ROM Pack V",
|
||||
"ne": "(USA) (Test Program)",
|
||||
"gc": "",
|
||||
"rc": 2539003264,
|
||||
"rs": 32768,
|
||||
"lg": "En",
|
||||
"rg": "USA"
|
||||
},
|
||||
"8f5d0235df4ae4b8840b669c0dd979a177054eeb": {
|
||||
"gn": "2440 ROM Pack",
|
||||
"ne": "(USA) (Test Program)",
|
||||
"gc": "",
|
||||
"rc": 2056477162,
|
||||
"rs": 32768,
|
||||
"lg": "En",
|
||||
"rg": "USA"
|
||||
},
|
||||
"b4abb29a67c3351eaf60be9d89320fc927937618": {
|
||||
"gn": "Aladdin",
|
||||
"ne": "(Europe) (SGB Enhanced)",
|
||||
|
|
@ -10981,7 +10954,7 @@
|
|||
},
|
||||
"0129d7a3c58b6271e6d4cdab034c397e0e355aae": {
|
||||
"gn": "Loppi Puzzle Magazine - Kangaeru Puzzle Dai-2-gou",
|
||||
"ne": "(Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP) [b]",
|
||||
"ne": "(Japan) (Rev 1) (SGB Enhanced, GB Compatible) (NP)",
|
||||
"gc": "DMG-B62J",
|
||||
"rc": 665526663,
|
||||
"rs": 262144,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,19 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"BX2006_TSOP_64BALL with GL256S"
|
||||
"BX2006_TSOP_64BALL with GL256S",
|
||||
"BGA64B-71-TV-DEEP with 256M29EML",
|
||||
"FunnyPlaying MidnightTrace 32 MiB Flash Cart"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x02, 0x00, 0x7D, 0x22 ],
|
||||
[ 0x8A, 0x00, 0x7D, 0x22 ],
|
||||
[ 0x02, 0x00, 0x7D, 0x22 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
"sector_size":0x20000,
|
||||
"chip_erase_timeout":120,
|
||||
"chip_erase_timeout":200,
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
"Generic Flash Cartridge (0/90)"
|
||||
],
|
||||
"voltage":3.3,
|
||||
"chip_erase_timeout":300,
|
||||
"sector_size_from_cfi":true,
|
||||
"command_set":"INTEL",
|
||||
"commands":{
|
||||
|
|
@ -23,7 +22,7 @@
|
|||
],
|
||||
"sector_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0xFFFF ]
|
||||
],
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@
|
|||
"4050_4400_4000_4350_36L0R_V5 with M36L0R8060T",
|
||||
"36L0R8-39VF512 with M36L0R8060T",
|
||||
"4050_4400_4000_4350_36L0R_V5 with 4050L0YTQ2",
|
||||
"4350Q2 with 4050V0YBQ1"
|
||||
"4350Q2 with 4050V0YBQ1",
|
||||
"M36XXX_T32_32D_16D with M36L0R8060T",
|
||||
"2006-36-71_V2 with M36L0R8060B"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x20, 0x00, 0x0D, 0x88 ],
|
||||
|
|
@ -14,7 +16,9 @@
|
|||
[ 0x20, 0x00, 0x0E, 0x88 ],
|
||||
[ 0x20, 0x00, 0x0E, 0x88 ],
|
||||
[ 0x8A, 0x00, 0x0E, 0x88 ],
|
||||
[ 0x8A, 0x00, 0x1C, 0x88 ]
|
||||
[ 0x8A, 0x00, 0x1C, 0x88 ],
|
||||
[ 0x20, 0x00, 0x0E, 0x88 ],
|
||||
[ 0x20, 0x00, 0x0D, 0x88 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
|
|
|
|||
47
FlashGBX/config/fc_AGB_M5M29HD528.txt
Normal file
47
FlashGBX/config/fc_AGB_M5M29HD528.txt
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"M5M29-39VF512 with M5M29HD528"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x1C, 0x00, 0xFA, 0x00 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
"sector_size":[
|
||||
[0x4000, 8],
|
||||
[0x20000, 255]
|
||||
],
|
||||
"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, 0xFFFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0, 0x70 ],
|
||||
[ 0, 0x40 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ 0, 0x80, 0x80 ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -9,8 +9,7 @@
|
|||
"AGB-E05-02 with M29W128FH",
|
||||
"2006_TSOP_64BALL_6106 with W29GL128SH9B",
|
||||
"AGB-E05-02 with JS28F128",
|
||||
"AGB-E05-03H with M29W128GH",
|
||||
"BGA64B-71-TV-DEEP with 256M29EML"
|
||||
"AGB-E05-03H with M29W128GH"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x02, 0x00, 0x7D, 0x22 ],
|
||||
|
|
@ -21,8 +20,7 @@
|
|||
[ 0x20, 0x00, 0x7D, 0x22 ],
|
||||
[ 0xEF, 0x00, 0x7D, 0x22 ],
|
||||
[ 0x8A, 0x00, 0x7D, 0x22 ],
|
||||
[ 0x20, 0x00, 0x7D, 0x22 ],
|
||||
[ 0x8A, 0x00, 0x7D, 0x22 ]
|
||||
[ 0x20, 0x00, 0x7D, 0x22 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x1000000,
|
||||
|
|
|
|||
58
FlashGBX/config/fc_AGB_TE28F128.txt
Normal file
58
FlashGBX/config/fc_AGB_TE28F128.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"DL9SEC GBA flashcart with TE28F128"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x89, 0x00, 0x18, 0x00 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x1000000,
|
||||
"sector_size_from_cfi":true,
|
||||
"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 ],
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0xFFFF ]
|
||||
],
|
||||
"buffer_write":[
|
||||
[ "SA", 0xE8 ],
|
||||
[ "SA", "BS" ],
|
||||
[ "PA", "PD" ],
|
||||
[ "SA", 0xD0 ],
|
||||
[ "SA", 0xFF ]
|
||||
],
|
||||
"buffer_write_wait_for":[
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ null, null, null ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0, 0x70 ],
|
||||
[ 0, 0x10 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ 0, 0x80, 0x80 ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
58
FlashGBX/config/fc_AGB_TE28F256.txt
Normal file
58
FlashGBX/config/fc_AGB_TE28F256.txt
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"DL9SEC GBA flashcart with TE28F256"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x89, 0x00, 0x1D, 0x00 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
"sector_size_from_cfi":true,
|
||||
"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 ],
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0xFFFF ]
|
||||
],
|
||||
"buffer_write":[
|
||||
[ "SA", 0xE8 ],
|
||||
[ "SA", "BS" ],
|
||||
[ "PA", "PD" ],
|
||||
[ "SA", 0xD0 ],
|
||||
[ "SA", 0xFF ]
|
||||
],
|
||||
"buffer_write_wait_for":[
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ null, null, null ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0, 0x70 ],
|
||||
[ 0, 0x10 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ 0, 0x80, 0x80 ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
59
FlashGBX/config/fc_AGB_TH50VSF3680.txt
Normal file
59
FlashGBX/config/fc_AGB_TH50VSF3680.txt
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"3680x2 with TH50VSF3680"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x98, 0x00, 0x93, 0x00 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x800000,
|
||||
"sector_size":[
|
||||
[0x10000, 127],
|
||||
[0x2000, 8],
|
||||
[0x10000, 127],
|
||||
[0x2000, 8]
|
||||
],
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x90 ]
|
||||
],
|
||||
"read_cfi":[
|
||||
[ 0xAA, 0x98 ]
|
||||
],
|
||||
"sector_erase":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x80 ],
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ "SA", 0x30 ]
|
||||
],
|
||||
"sector_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0xFFFF, 0xFFFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0xA0 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
88
FlashGBX/config/fc_AGB_iG_32MB_EEPROM.txt
Normal file
88
FlashGBX/config/fc_AGB_iG_32MB_EEPROM.txt
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"insideGadgets 32 MiB + EEPROM"
|
||||
],
|
||||
"flash_ids":[],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x1FFFF00,
|
||||
"sector_size":0x20000,
|
||||
"chip_erase_timeout":300,
|
||||
"single_write_first_256_bytes":true,
|
||||
"rtc":true,
|
||||
"rumble":true,
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x90 ]
|
||||
],
|
||||
"read_cfi":[
|
||||
[ 0xAA, 0x98 ]
|
||||
],
|
||||
"sector_erase":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x80 ],
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ "SA", 0x30 ]
|
||||
],
|
||||
"sector_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 0xFFFF, 0xFFFF ]
|
||||
],
|
||||
"chip_erase":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x80 ],
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x10 ]
|
||||
],
|
||||
"chip_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ 0, 0xFFFF, 0xFFFF ]
|
||||
],
|
||||
"buffer_write":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ "SA", 0x25 ],
|
||||
[ "SA", "BS" ],
|
||||
[ "PA", "PD" ],
|
||||
[ "SA", 0x29 ]
|
||||
],
|
||||
"buffer_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", "PD", 0xFFFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0xA0 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
59
FlashGBX/config/fc_DMG_26LV160BTC.txt
Normal file
59
FlashGBX/config/fc_DMG_26LV160BTC.txt
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"SD007_BV5_V3 with 26LV160BTC"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xC1, 0x00, 0x4A, 0x21 ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x200000,
|
||||
"start_addr":0,
|
||||
"first_bank":1,
|
||||
"write_pin":"WR",
|
||||
"sector_size":[
|
||||
[0x4000, 1],
|
||||
[0x2000, 2],
|
||||
[0x8000, 1],
|
||||
[0x10000, 31]
|
||||
],
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0xAAA, 0xA9 ],
|
||||
[ 0x555, 0x56 ],
|
||||
[ 0xAAA, 0x90 ]
|
||||
],
|
||||
"sector_erase":[
|
||||
[ 0xAAA, 0xA9 ],
|
||||
[ 0x555, 0x56 ],
|
||||
[ 0xAAA, 0x80 ],
|
||||
[ 0xAAA, 0xA9 ],
|
||||
[ 0x555, 0x56 ],
|
||||
[ "SA", 0x30 ]
|
||||
],
|
||||
"sector_erase_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ "SA", 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 ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,8 @@
|
|||
"BennVenn MBC3000 RTC cart"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xC2, 0xC2, 0xCB, 0xCB ]
|
||||
[ 0xC2, 0xC2, 0xCB, 0xCB ],
|
||||
[ 0xC2, 0xC2, 0x7E, 0x7E ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x800000,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
"BennVenn MBC3000 RTC cart (ROM2)"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xC2, 0xC2, 0xCB, 0xCB ]
|
||||
[ 0xC2, 0xC2, 0xCB, 0xCB ],
|
||||
[ 0xC2, 0xC2, 0x7E, 0x7E ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x400000,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"insideGadgets 4 MiB (S29JL032J)"
|
||||
"insideGadgets 4 MiB (S29JL032J)",
|
||||
"Gamebank-web DMG-29W-04 with M29W320ET"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x01, 0x01, 0x56, 0x56 ]
|
||||
[ 0x01, 0x01, 0x56, 0x56 ],
|
||||
[ 0x20, 0x20, 0x56, 0x56 ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x400000,
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"insideGadgets 8 MiB"
|
||||
"insideGadgets 8 MiB",
|
||||
"FunnyPlaying MidnightTrace 4 MiB Flash Cart"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x01, 0x01, 0x7E, 0x7E ],
|
||||
[ 0x01, 0x01, 0x7E, 0x7E ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"voltage_variants":true,
|
||||
"flash_size":0x800000,
|
||||
"start_addr":0x4000,
|
||||
"first_bank":0,
|
||||
|
|
|
|||
|
|
@ -514,7 +514,10 @@ class GbxDevice:
|
|||
else:
|
||||
return struct.unpack(">H", self.ReadROM(address >> 1, length))[0]
|
||||
else:
|
||||
return self.ReadROM(address, length)
|
||||
if agb_save_flash:
|
||||
return self.ReadRAM(address, length, command=self.DEVICE_CMD["AGB_CART_READ_SRAM"])
|
||||
else:
|
||||
return self.ReadROM(address, length)
|
||||
|
||||
def _cart_write(self, address, value, flashcart=False, sram=False):
|
||||
dprint("Writing to cartridge: 0x{:X} = 0x{:X} (args: {:s}, {:s})".format(address, value & 0xFF, str(flashcart), str(sram)))
|
||||
|
|
@ -558,7 +561,7 @@ class GbxDevice:
|
|||
buffer.extend(struct.pack("B", 1 if flashcart else 0))
|
||||
buffer.extend(struct.pack("B", num))
|
||||
for i in range(0, num):
|
||||
#dprint("Writing to cartridge: 0x{:X} = 0x{:X} ({:d} of {:d})".format(commands[i][0], commands[i][1], i+1, num))
|
||||
dprint("Writing to cartridge: 0x{:X} = 0x{:X} ({:d} of {:d})".format(commands[i][0], commands[i][1], i+1, num))
|
||||
if self.MODE == "AGB" and flashcart:
|
||||
buffer.extend(struct.pack(">I", commands[i][0] >> 1))
|
||||
else:
|
||||
|
|
@ -767,23 +770,24 @@ class GbxDevice:
|
|||
if (self.ReadROM(0x1FFE000, 0x0C) == b"AGBFLASHDACS"):
|
||||
data["dacs_8m"] = True
|
||||
|
||||
data["rtc_string"] = "Not available"
|
||||
if checkRtc and data["logo_correct"] is True and header[0xC5] == 0 and header[0xC7] == 0 and header[0xC9] == 0:
|
||||
_agb_gpio = AGB_GPIO(args={"rtc":True}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, cart_powercycle_fncptr=self.CartPowerCycle, clk_toggle_fncptr=self._clk_toggle)
|
||||
has_rtc = _agb_gpio.HasRTC()
|
||||
data["has_rtc"] = has_rtc is True
|
||||
if has_rtc is not True:
|
||||
data["no_rtc_reason"] = has_rtc
|
||||
data["has_rtc"] = False
|
||||
else:
|
||||
data["rtc_buffer"] = _agb_gpio.ReadRTC()
|
||||
|
||||
try:
|
||||
data["rtc_string"] = _agb_gpio.GetRTCString()
|
||||
except:
|
||||
data["rtc_string"] = "Invalid data"
|
||||
try:
|
||||
data["rtc_string"] = _agb_gpio.GetRTCString()
|
||||
except Exception as e:
|
||||
dprint("RTC exception:", str(e.args[0]))
|
||||
data["has_rtc"] = False
|
||||
else:
|
||||
data["has_rtc"] = False
|
||||
data["no_rtc_reason"] = None
|
||||
data["rtc_string"] = "Not available"
|
||||
|
||||
if data["ereader"] is True:
|
||||
bank = 0
|
||||
|
|
@ -812,7 +816,7 @@ class GbxDevice:
|
|||
|
||||
if self.MODE == "DMG": #and setPinsAsInputs:
|
||||
self._write(self.DEVICE_CMD["SET_ADDR_AS_INPUTS"])
|
||||
|
||||
|
||||
return data
|
||||
|
||||
def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=True):
|
||||
|
|
@ -1820,7 +1824,7 @@ class GbxDevice:
|
|||
if d_swap is not None and d_swap != ( 0, 0 ):
|
||||
for i in range(0, len(buffer)):
|
||||
buffer[i] = bitswap(buffer[i], d_swap)
|
||||
|
||||
|
||||
cfi_parsed = ParseCFI(buffer)
|
||||
try:
|
||||
if d_swap is not None:
|
||||
|
|
@ -1853,7 +1857,7 @@ class GbxDevice:
|
|||
for i in range(0, len(method['read_identifier'])):
|
||||
self._cart_write(method['read_identifier'][i][0], method["read_identifier"][i][1], flashcart=True)
|
||||
flash_id = self.ReadROM(0, 8)
|
||||
|
||||
|
||||
if self.MODE == "DMG":
|
||||
method_string = "[" + we.ljust(5) + "/{:4X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
|
||||
else:
|
||||
|
|
@ -2072,7 +2076,7 @@ class GbxDevice:
|
|||
|
||||
buffer_len = 0x4000
|
||||
|
||||
#self.INFO["dump_info"]["timestamp"] = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat()
|
||||
self.INFO["dump_info"] = {}
|
||||
self.INFO["dump_info"]["timestamp"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
|
||||
self.INFO["dump_info"]["file_name"] = args["path"]
|
||||
self.INFO["dump_info"]["file_size"] = args["rom_size"]
|
||||
|
|
@ -2101,9 +2105,6 @@ class GbxDevice:
|
|||
self._set_fw_variable("DMG_READ_CS_PULSE", 1)
|
||||
_mbc.EnableMapper()
|
||||
self._set_fw_variable("DMG_READ_CS_PULSE", 0)
|
||||
elif _mbc.GetName() == "Sachen":
|
||||
start_bank = int(args["rom_size"] / 0x4000)
|
||||
_mbc.SetStartBank(start_bank)
|
||||
else:
|
||||
_mbc.EnableMapper()
|
||||
|
||||
|
|
@ -2111,6 +2112,9 @@ class GbxDevice:
|
|||
rom_banks = _mbc.GetROMBanks(rom_size)
|
||||
rom_bank_size = _mbc.GetROMBankSize()
|
||||
size = _mbc.GetROMSize()
|
||||
|
||||
#if _mbc.GetName() == "Datel MegaMem":
|
||||
# args["rom_size"] = self.INFO["dump_info"]["file_size"] = rom_size = size = _mbc.GetMaxROMSize()
|
||||
|
||||
elif self.MODE == "AGB":
|
||||
self.INFO["dump_info"]["mapper_type"] = None
|
||||
|
|
@ -2381,6 +2385,7 @@ class GbxDevice:
|
|||
self.DEVICE.reset_input_buffer()
|
||||
self.DEVICE.reset_output_buffer()
|
||||
|
||||
if "eeprom_data" in self.INFO["dump_info"]: del(self.INFO["dump_info"]["eeprom_data"])
|
||||
if "EEPROM" in temp_ver and len(buffer) == 0x2000000:
|
||||
padding_byte = buffer[0x1FFFEFF]
|
||||
dprint("Replacing unmapped ROM data of cartridge (32 MiB ROM + EEPROM save type) with the original padding byte of 0x{:02X}.".format(padding_byte))
|
||||
|
|
@ -2534,6 +2539,8 @@ class GbxDevice:
|
|||
return False
|
||||
buffer_len = 0x1000
|
||||
(agb_flash_chip, _) = ret
|
||||
if agb_flash_chip == 0xBF5B: # Bootlegs
|
||||
buffer_len = 0x800
|
||||
elif args["save_type"] == 6: # DACS
|
||||
self._write(self.DEVICE_CMD["AGB_BOOTUP_SEQUENCE"], wait=True)
|
||||
empty_data_byte = 0xFF
|
||||
|
|
@ -2654,7 +2661,10 @@ class GbxDevice:
|
|||
end_address = min(save_size, bank_size)
|
||||
|
||||
if save_size > bank_size:
|
||||
if args["save_type"] == 5: # FLASH 1M
|
||||
if args["save_type"] == 8 or agb_flash_chip == 0xBF5B: # Bootleg 1M
|
||||
dprint("Switching to bootleg save bank {:d}".format(bank))
|
||||
self._cart_write(0x1000000, bank)
|
||||
elif args["save_type"] == 5: # FLASH 1M
|
||||
dprint("Switching to FLASH bank {:d}".format(bank))
|
||||
cmds = [
|
||||
[ 0x5555, 0xAA ],
|
||||
|
|
@ -2663,9 +2673,6 @@ class GbxDevice:
|
|||
[ 0, bank ]
|
||||
]
|
||||
self._cart_write_flash(cmds)
|
||||
elif args["save_type"] == 8: # SRAM 1M
|
||||
dprint("Switching to SRAM bank {:d}".format(bank))
|
||||
self._cart_write(0x1000000, bank)
|
||||
else:
|
||||
dprint("Unknown bank switching method")
|
||||
time.sleep(0.05)
|
||||
|
|
@ -2749,7 +2756,7 @@ class GbxDevice:
|
|||
elif self.MODE == "AGB" and args["save_type"] in (1, 2): # EEPROM
|
||||
self.WriteRAM(address=int(pos/8), buffer=buffer[buffer_offset:buffer_offset+buffer_len], command=command)
|
||||
elif self.MODE == "AGB" and args["save_type"] in (4, 5): # FLASH
|
||||
sector_address = int(pos / buffer_len)
|
||||
sector_address = pos % 0x10000
|
||||
if agb_flash_chip == 0x1F3D: # Atmel AT29LV512
|
||||
self.WriteRAM(address=int(pos/128), buffer=buffer[buffer_offset:buffer_offset+buffer_len], command=command)
|
||||
else:
|
||||
|
|
@ -2760,14 +2767,14 @@ class GbxDevice:
|
|||
[ 0x5555, 0x80 ],
|
||||
[ 0x5555, 0xAA ],
|
||||
[ 0x2AAA, 0x55 ],
|
||||
[ sector_address << 12, 0x30 ]
|
||||
[ sector_address, 0x30 ]
|
||||
]
|
||||
self._cart_write_flash(cmds)
|
||||
sr = 0
|
||||
lives = 50
|
||||
while True:
|
||||
time.sleep(0.01)
|
||||
sr = self._cart_read(sector_address << 12, agb_save_flash=True)
|
||||
sr = self._cart_read(sector_address, agb_save_flash=True)
|
||||
dprint("Data Check: 0x{:X} == 0xFFFF? {:s}".format(sr, str(sr == 0xFFFF)))
|
||||
if sr == 0xFFFF: break
|
||||
lives -= 1
|
||||
|
|
@ -2775,12 +2782,12 @@ class GbxDevice:
|
|||
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
|
||||
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 == 15):
|
||||
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)
|
||||
else:
|
||||
self.WriteRAM(address=pos, buffer=buffer[buffer_offset:buffer_offset+buffer_len], command=command)
|
||||
elif self.MODE == "AGB" and args["save_type"] == 6: # DACS
|
||||
sector_address = pos+0x1F00000
|
||||
sector_address = pos + 0x1F00000
|
||||
if sector_address in (0x1F00000, 0x1F10000, 0x1F20000, 0x1F30000, 0x1F40000, 0x1F50000, 0x1F60000, 0x1F70000, 0x1F80000, 0x1F90000, 0x1FA0000, 0x1FB0000, 0x1FC0000, 0x1FD0000, 0x1FE0000, 0x1FF0000, 0x1FF2000, 0x1FF4000, 0x1FF6000, 0x1FF8000, 0x1FFA000, 0x1FFC000):
|
||||
dprint("DACS: Now at sector 0x{:X}".format(sector_address))
|
||||
cmds = [
|
||||
|
|
@ -2926,7 +2933,8 @@ class GbxDevice:
|
|||
msg += "- 0x{:06X}: {:02X}≠{:02X}\n".format(i, data1, data2)
|
||||
elif len(msg.split("\n")) == 11:
|
||||
msg += "(more than 10 differences found)\n"
|
||||
break
|
||||
else:
|
||||
pass
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The save data was written completely, but {:d} byte(s) ({:.2f}%) didn’t pass the verification check.\n\n{:s}".format(count, (count / len(self.INFO["data"]) * 100), msg[:-1]), "abortable":False})
|
||||
return False
|
||||
else:
|
||||
|
|
@ -2981,8 +2989,16 @@ class GbxDevice:
|
|||
print("Note: The last 256 bytes of this 32 MiB ROM will not be written as this area is reserved by the EEPROM save type.")
|
||||
data_import = data_import[:0x1FFFF00]
|
||||
|
||||
# Fix header
|
||||
# Fix bootlogo and header
|
||||
if "fix_bootlogo" in args and isinstance(args["fix_bootlogo"], bytearray):
|
||||
dstr = ''.join(format(x, '02X') for x in args["fix_bootlogo"])
|
||||
dprint("Replacing bootlogo data with", dstr)
|
||||
if self.MODE == "DMG":
|
||||
data_import[0x104:0x134] = args["fix_bootlogo"]
|
||||
elif self.MODE == "AGB":
|
||||
data_import[0x04:0xA0] = args["fix_bootlogo"]
|
||||
if "fix_header" in args and args["fix_header"]:
|
||||
dprint("Fixing header checksums")
|
||||
if self.MODE == "DMG":
|
||||
temp = RomFileDMG(data_import[0:0x200]).FixHeader()
|
||||
elif self.MODE == "AGB":
|
||||
|
|
@ -3386,7 +3402,10 @@ class GbxDevice:
|
|||
if "bl_save" in args:
|
||||
data_import = bytearray([0] * bl_sectors[0][0]) + data_import
|
||||
else:
|
||||
write_sectors = sector_offsets
|
||||
write_sectors = []
|
||||
for item in sector_offsets:
|
||||
if item[0] < len(data_import):
|
||||
write_sectors.append(item)
|
||||
|
||||
dprint("Sectors to update:", write_sectors)
|
||||
# ↑↑↑ Read Sector Map
|
||||
|
|
@ -3398,6 +3417,7 @@ class GbxDevice:
|
|||
chip_erase = False
|
||||
else:
|
||||
chip_erase = True
|
||||
dprint("Erasing the entire flash chip")
|
||||
if flashcart.ChipErase() is False:
|
||||
return False
|
||||
elif flashcart.SupportsSectorErase() is False:
|
||||
|
|
|
|||
Binary file not shown.
12
README.md
12
README.md
|
|
@ -114,6 +114,8 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- Ferrante Crafts cart 32 KB
|
||||
- Ferrante Crafts cart 64 KB
|
||||
- Ferrante Crafts cart 512 KB
|
||||
- FunnyPlaying MidnightTrace 4 MiB Flash Cart
|
||||
- Gamebank-web DMG-29W-04 with M29W320ET
|
||||
- GB-CART32K-A with SST39SF020A
|
||||
- GB Smart 32M
|
||||
- HDR Game Boy Camera Flashcart
|
||||
|
|
@ -137,6 +139,8 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- Development AGB Cartridge 64M Flash S, E201843
|
||||
- Development AGB Cartridge 128M Flash S, E201850
|
||||
- Development AGB Cartridge 256M Flash S, E201868
|
||||
- DL9SEC GBA flashcart with TE28F128
|
||||
- DL9SEC GBA flashcart with TE28F256
|
||||
- Flash Advance Pro 256M
|
||||
- Flash2Advance 128M (with 2× 28F640J3A120)
|
||||
- Flash2Advance 256M (with 2× 28F128J3A150)
|
||||
|
|
@ -144,6 +148,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- Flash2Advance Ultra 64M (with 2× 28F320C3B)
|
||||
- Flash2Advance Ultra 256M (with 8× 3204C3B100)
|
||||
- Flash Advance Card 64M (with 28F640J3A120)
|
||||
- FunnyPlaying MidnightTrace 32 MiB Flash Cart
|
||||
- insideGadgets 16 MiB, 64K EEPROM with Solar Sensor and RTC options
|
||||
- insideGadgets 32 MiB, 1M FLASH with RTC option
|
||||
- insideGadgets 32 MiB, 512K FLASH
|
||||
|
|
@ -183,6 +188,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- SD007_BV5_DRV with S29GL032M90TFIR4
|
||||
- SD007_BV5_V2 with HY29LV160TT
|
||||
- SD007_BV5_V2 with MX29LV320BTC
|
||||
- SD007_BV5_V3 with 26LV160BTC
|
||||
- SD007_BV5_V3 with 29LV160BE-90PFTN
|
||||
- SD007_BV5_V3 with HY29LV160BT-70
|
||||
- SD007_BV5_V3 with AM29LV160MB
|
||||
|
|
@ -220,9 +226,11 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- 0121 with 0121M0Y0BE
|
||||
- 100BS6600_48BALL_V4 with 6600M0U0BE
|
||||
- 100SOP with MSP55LV100S
|
||||
- 2006-36-71_V2 with M36L0R8060B
|
||||
- 2006_TSOP_64BALL_6106 with W29GL128SH9B
|
||||
- 28F256L03B-DRV with 256L30B
|
||||
- 29LV128DBT2C-90Q and ALTERA CPLD
|
||||
- 3680x2 with TH50VSF3680
|
||||
- 36L0R8-39VF512 with M36L0R8060B
|
||||
- 36L0R8-39VF512 with M36L0R8060T
|
||||
- 4000L0ZBQ0 DRV with 3000L0YBQ0
|
||||
|
|
@ -267,6 +275,8 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- F864-3 with M36L0R7050B
|
||||
- GA-07 with unlabeled flash chip
|
||||
- GE28F128W30 with 128W30B0
|
||||
- M36XXX_T32_32D_16D with M36L0R806
|
||||
- M5M29-39VF512 with M5M29HD528
|
||||
- M5M29G130AN (no PCB text)
|
||||
- M6MGJ927 (no PCB text)
|
||||
- MSP54LV512 (no PCB text)
|
||||
|
|
@ -308,7 +318,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, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, 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, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, 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, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, yosoo, Zeii, Zelante, Zoo, zvxr
|
||||
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, 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, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr
|
||||
|
||||
## DISCLAIMER
|
||||
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -8,7 +8,7 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read(
|
|||
|
||||
setuptools.setup(
|
||||
name="FlashGBX",
|
||||
version="3.31",
|
||||
version="3.32",
|
||||
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",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user