mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-04-24 23:37:34 -05:00
3.21
This commit is contained in:
parent
3b360b28d0
commit
288dbf8216
BIN
.github/01.png
vendored
BIN
.github/01.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 50 KiB |
BIN
.github/02.png
vendored
BIN
.github/02.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 89 KiB |
17
CHANGES.md
17
CHANGES.md
|
|
@ -1,6 +1,19 @@
|
|||
# Release notes
|
||||
### v3.21 (released 2023-01-16)
|
||||
- Bundles GBxCart RW v1.4/v1.4a firmware version R39+L8 (adds support for insideGadgets WonderSwan and Game Gear flash carts)
|
||||
- Added support for SD007_48BALL_SOP28 with M29W320ET *(thanks DevDavisNunez)*
|
||||
- Added support for the BennVenn MBC3000 RTC cart *(thanks LucentW)*
|
||||
- Added support for Flash2Advance Ultra 256M with 8× 3204C3B100 *(thanks djeddit)*
|
||||
- Added support for SD007_T40_64BALL_SOJ28 with 29LV016T *(thanks Stitch)*
|
||||
- Confirmed support for SD007_T40_64BALL_S71_TV_TS28 with TC58FVB016FT-85 *(thanks edo999)*
|
||||
- Added support for F864-3 with M36L0R7050B *(thanks s1cp)*
|
||||
- Allowed for switching between different Write Enable pins during chip erase and sector erase command sequences via a third parameter (“WR” or “AUDIO”) *(thanks ALXCO-Hardware for the suggestion)*
|
||||
- Added support for the Squareboi 4 MB (2× 2 MB) cart *(thanks ALXCO-Hardware)*
|
||||
- Added an option to limit the baud rate for GBxCart RW v1.4/v1.4a
|
||||
- Minor bug fixes and improvements *(thanks gboh, Grender and orangeglo)*
|
||||
|
||||
### v3.20 (released 2022-11-30)
|
||||
- Bundles GBxCart RW v1.4/v1.4a firmware version R38+L8
|
||||
- Bundles GBxCart RW v1.4/v1.4a firmware version R38+L8 (minor improvements)
|
||||
- Will now retry failed flash sector writes a few times before stopping the process (requires firmware version L1+)
|
||||
- Added delta ROM writing (only write the difference between two ROMs); requires both the original <name>.<ext> ROM file and the changed <name>.delta.<ext> ROM file in the same directory (requires firmware version L1+) *(thanks djeddit for the suggestion)*
|
||||
- Fixed support for Flash2Advance Ultra 64M with 2× 28F320C3B
|
||||
|
|
@ -234,7 +247,7 @@
|
|||
- Added support for SD007_TSOP_48BALL_V10 with M29W320DT *(thanks Jayro)*
|
||||
- Fixed a problem of reading from a certain type of cartridge that uses the GL256S flash chip *(thanks marv17)*
|
||||
- Added support for B11 with 26L6420MC-90 *(thanks dyf2007)*
|
||||
- Added support for DIY carts with MBC3 and MX29LV640 *(thanks eveningmoose)*
|
||||
- Added support for DIY carts with MX29LV640 *(thanks eveningmoose)*
|
||||
|
||||
### v2.1 (released 2021-05-05)
|
||||
- Fixed support for SD007_TSOP_29LV017D with L017D70VC *(thanks marv17 and 90sFlav)*
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
# Author: Lesserkuma (github.com/lesserkuma)
|
||||
|
||||
import traceback
|
||||
from serial import SerialException
|
||||
from . import pyside as PySide2
|
||||
|
||||
class DataTransfer(PySide2.QtCore.QThread):
|
||||
|
|
@ -25,6 +26,8 @@ class DataTransfer(PySide2.QtCore.QThread):
|
|||
return not self.FINISHED
|
||||
|
||||
def run(self):
|
||||
tb = ""
|
||||
error = None
|
||||
try:
|
||||
if self.CONFIG == None:
|
||||
pass
|
||||
|
|
@ -34,7 +37,19 @@ class DataTransfer(PySide2.QtCore.QThread):
|
|||
self.CONFIG['port'].TransferData(self.CONFIG, self.updateProgress)
|
||||
self.FINISHED = True
|
||||
|
||||
except SerialException as e:
|
||||
if "GetOverlappedResult failed" in e.args[0]:
|
||||
self.updateProgress.emit({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The USB connection was lost during a transfer. Try different USB cables, reconnect the device, restart the software and try again.", "abortable":False})
|
||||
self.FINISHED = True
|
||||
return
|
||||
tb = traceback.format_exc()
|
||||
error = e
|
||||
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
self.updateProgress.emit({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"An unresolvable error has occured. See console output for more information. Reconnect the device, restart the software and try again.\n\n{:s}: {:s}".format(type(e).__name__, str(e)), "abortable":False})
|
||||
tb = traceback.format_exc()
|
||||
error = e
|
||||
|
||||
if error is not None:
|
||||
print(tb)
|
||||
self.updateProgress.emit({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"An unresolvable error has occured. See console output for more information. Reconnect the device, restart the software and try again.\n\n{:s}: {:s}".format(type(error).__name__, str(error)), "abortable":False})
|
||||
self.FINISHED = True
|
||||
|
|
|
|||
|
|
@ -372,6 +372,7 @@ class FlashGBX_CLI():
|
|||
self.CONN.INFO["last_action"] = 0
|
||||
|
||||
def FindDevices(self, port=None):
|
||||
# pylint: disable=global-variable-not-assigned
|
||||
global hw_devices
|
||||
for hw_device in hw_devices:
|
||||
dev = hw_device.GbxDevice()
|
||||
|
|
@ -607,7 +608,7 @@ class FlashGBX_CLI():
|
|||
Util.AGB_Global_CRC32 = 0
|
||||
db_agb_entry = None
|
||||
if os.path.exists("{0:s}/db_AGB.json".format(self.CONFIG_PATH)):
|
||||
with open("{0:s}/db_AGB.json".format(self.CONFIG_PATH)) as f:
|
||||
with open("{0:s}/db_AGB.json".format(self.CONFIG_PATH), encoding="UTF-8") as f:
|
||||
db_agb = f.read()
|
||||
db_agb = json.loads(db_agb)
|
||||
if data["header_sha1"] in db_agb.keys():
|
||||
|
|
|
|||
|
|
@ -200,7 +200,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.mnuConfig.addAction("Prefer full &chip erase over sector erase when both available", lambda: self.SETTINGS.setValue("PreferChipErase", str(self.mnuConfig.actions()[2].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("&Verify data after writing", lambda: self.SETTINGS.setValue("VerifyWrittenData", str(self.mnuConfig.actions()[3].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("&Limit voltage to 3.3V when detecting Game Boy flash cartridges", lambda: self.SETTINGS.setValue("AutoDetectLimitVoltage", str(self.mnuConfig.actions()[4].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("Always &generate ROM dump reports", lambda: self.SETTINGS.setValue("GenerateDumpReports", str(self.mnuConfig.actions()[5].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addAction("Limit &baud rate to 1Mbps for GBxCart RW v1.4 devices", lambda: [ self.SETTINGS.setValue("LimitBaudRate", str(self.mnuConfig.actions()[5].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")), self.SetLimitBaudRate() ])
|
||||
self.mnuConfig.addAction("Always &generate ROM dump reports", lambda: self.SETTINGS.setValue("GenerateDumpReports", str(self.mnuConfig.actions()[6].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
|
||||
self.mnuConfig.addSeparator()
|
||||
self.mnuConfig.addAction("Re-&enable suppressed messages", self.ReEnableMessages)
|
||||
self.mnuConfig.addSeparator()
|
||||
|
|
@ -211,12 +212,14 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.mnuConfig.actions()[3].setCheckable(True)
|
||||
self.mnuConfig.actions()[4].setCheckable(True)
|
||||
self.mnuConfig.actions()[5].setCheckable(True)
|
||||
self.mnuConfig.actions()[6].setCheckable(True)
|
||||
self.mnuConfig.actions()[0].setChecked(self.SETTINGS.value("UpdateCheck") == "enabled")
|
||||
self.mnuConfig.actions()[1].setChecked(self.SETTINGS.value("SaveFileNameAddDateTime", default="disabled") == "enabled")
|
||||
self.mnuConfig.actions()[2].setChecked(self.SETTINGS.value("PreferChipErase", default="disabled") == "enabled")
|
||||
self.mnuConfig.actions()[3].setChecked(self.SETTINGS.value("VerifyWrittenData", default="enabled") == "enabled")
|
||||
self.mnuConfig.actions()[4].setChecked(self.SETTINGS.value("AutoDetectLimitVoltage", default="disabled") == "enabled")
|
||||
self.mnuConfig.actions()[5].setChecked(self.SETTINGS.value("GenerateDumpReports", default="disabled") == "enabled")
|
||||
self.mnuConfig.actions()[5].setChecked(self.SETTINGS.value("LimitBaudRate", default="disabled") == "enabled")
|
||||
self.mnuConfig.actions()[6].setChecked(self.SETTINGS.value("GenerateDumpReports", default="disabled") == "enabled")
|
||||
|
||||
self.btnConfig.setMenu(self.mnuConfig)
|
||||
|
||||
|
|
@ -264,7 +267,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
def GuiCreateGroupBoxDMGCartInfo(self):
|
||||
self.grpDMGCartridgeInfo = QtWidgets.QGroupBox("Game Boy Cartridge Information")
|
||||
self.grpDMGCartridgeInfo.setMinimumWidth(352)
|
||||
self.grpDMGCartridgeInfo.setMinimumWidth(364)
|
||||
group_layout = QtWidgets.QVBoxLayout()
|
||||
group_layout.setContentsMargins(-1, 5, -1, -1)
|
||||
|
||||
|
|
@ -361,7 +364,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
def GuiCreateGroupBoxAGBCartInfo(self):
|
||||
self.grpAGBCartridgeInfo = QtWidgets.QGroupBox("Game Boy Advance Cartridge Information")
|
||||
self.grpAGBCartridgeInfo.setMinimumWidth(352)
|
||||
self.grpAGBCartridgeInfo.setMinimumWidth(364)
|
||||
group_layout = QtWidgets.QVBoxLayout()
|
||||
group_layout.setContentsMargins(-1, 5, -1, -1)
|
||||
|
||||
|
|
@ -459,6 +462,17 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.grpAGBCartridgeInfo.setLayout(group_layout)
|
||||
return self.grpAGBCartridgeInfo
|
||||
|
||||
def SetLimitBaudRate(self):
|
||||
if not self.CheckDeviceAlive(): return
|
||||
mode = self.CONN.GetMode()
|
||||
limit_baudrate = self.SETTINGS.value("LimitBaudRate")
|
||||
if limit_baudrate == "enabled":
|
||||
self.CONN.ChangeBaudRate(baudrate=1000000)
|
||||
else:
|
||||
self.CONN.ChangeBaudRate(baudrate=1700000)
|
||||
self.DisconnectDevice()
|
||||
self.FindDevices(connectToFirst=True, mode=mode)
|
||||
|
||||
def UpdateCheck(self):
|
||||
update_check = self.SETTINGS.value("UpdateCheck")
|
||||
if update_check is None:
|
||||
|
|
@ -614,7 +628,6 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
self.CONN = None
|
||||
if self.cmbDevice.count() == 0: self.lblDevice.setText("No connection.")
|
||||
return False
|
||||
|
||||
elif isinstance(ret, list):
|
||||
for i in range(0, len(ret)):
|
||||
status = ret[i][0]
|
||||
|
|
@ -637,6 +650,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
return False
|
||||
|
||||
if dev.IsConnected():
|
||||
dev.SetWriteDelay(enable=str(self.SETTINGS.value("WriteDelay", default="disabled")).lower() == "enabled")
|
||||
qt_app.processEvents()
|
||||
self.CONN = dev
|
||||
self.optDMG.setAutoExclusive(False)
|
||||
|
|
@ -722,6 +736,8 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
messages = []
|
||||
last_msg = ""
|
||||
|
||||
# pylint: disable=global-variable-not-assigned
|
||||
global hw_devices
|
||||
for hw_device in hw_devices:
|
||||
dev = hw_device.GbxDevice()
|
||||
|
|
@ -1178,6 +1194,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
if not just_erase:
|
||||
self.SETTINGS.setValue(setting_name, os.path.dirname(path))
|
||||
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 MB are not supported.", QtWidgets.QMessageBox.Ok)
|
||||
return
|
||||
|
|
@ -1234,7 +1253,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
mbc2 = Util.get_mbc_name(hdr["mapper_raw"])
|
||||
compatible_mbc = [ "None", "MBC2", "MBC3", "MBC5", "MBC7", "GBD", "G-MMC1", "HuC-1", "HuC-3" ]
|
||||
if mbc2 == "None":
|
||||
mbc = 0x19 # MBC5
|
||||
pass
|
||||
elif mbc2 != "None" and not (mbc1 in compatible_mbc and mbc2 in compatible_mbc):
|
||||
if "mbc" in carts[cart_type] and carts[cart_type]["mbc"] == "manual":
|
||||
msg_text = "The ROM file you selected uses a different mapper type than your current selection. What mapper should be used when writing the ROM?\n\nSelected mapper type: {:s}\nROM mapper type: {:s}".format(mbc1, mbc2)
|
||||
|
|
@ -1251,6 +1270,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
elif msgbox.clickedButton() == button_2:
|
||||
mbc = hdr["mapper_raw"]
|
||||
else:
|
||||
if mbc1 == "None": mbc1 = "None/Unknown"
|
||||
msg_text = "Warning: The ROM file you selected uses a different mapper type than your cartridge type. The ROM file may be incompatible with your cartridge.\n\nCartridge mapper type: {:s}\nROM mapper type: {:s}".format(mbc1, mbc2)
|
||||
answer = QtWidgets.QMessageBox.warning(self, "{:s} {:s}".format(APPNAME, VERSION), msg_text, QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Cancel)
|
||||
if answer == QtWidgets.QMessageBox.Cancel: return
|
||||
|
|
@ -1416,7 +1436,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
if not erase:
|
||||
filesize = os.path.getsize(path)
|
||||
if filesize > 0x200000: # reject too large files to avoid exploding RAM
|
||||
if filesize == 0 or filesize > 0x200000: # reject too large files to avoid exploding RAM
|
||||
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "The size of this file is not supported.", QtWidgets.QMessageBox.Ok)
|
||||
return
|
||||
|
||||
|
|
@ -1795,7 +1815,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
|
||||
db_agb_entry = None
|
||||
if os.path.exists("{0:s}/db_AGB.json".format(self.CONFIG_PATH)):
|
||||
with open("{0:s}/db_AGB.json".format(self.CONFIG_PATH)) as f:
|
||||
with open("{0:s}/db_AGB.json".format(self.CONFIG_PATH), encoding="UTF-8") as f:
|
||||
db_agb = f.read()
|
||||
db_agb = json.loads(db_agb)
|
||||
if data["header_sha1"] in db_agb.keys():
|
||||
|
|
@ -2413,5 +2433,9 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
else:
|
||||
qt_app.exec_() # PySide2
|
||||
|
||||
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
|
||||
os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
|
||||
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)
|
||||
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True)
|
||||
qt_app = QApplication(sys.argv)
|
||||
qt_app.setApplicationName(APPNAME)
|
||||
|
|
|
|||
|
|
@ -13,19 +13,24 @@ class Flashcart:
|
|||
CART_READ_FNCPTR = None
|
||||
CART_POWERCYCLE_FNCPTR = None
|
||||
PROGRESS_FNCPTR = None
|
||||
SET_WE_PIN_WR = None
|
||||
SET_WE_PIN_AUDIO = None
|
||||
DEFAULT_WE = None
|
||||
SECTOR_COUNT = 0
|
||||
SECTOR_POS = 0
|
||||
SECTOR_MAP = None
|
||||
CFI = None
|
||||
LAST_SR = 0x00
|
||||
|
||||
def __init__(self, config=None, cart_write_fncptr=None, cart_write_fast_fncptr=None, cart_read_fncptr=None, cart_powercycle_fncptr=None, progress_fncptr=None):
|
||||
def __init__(self, config=None, cart_write_fncptr=None, cart_write_fast_fncptr=None, cart_read_fncptr=None, cart_powercycle_fncptr=None, progress_fncptr=None, set_we_pin_wr=None, set_we_pin_audio=None):
|
||||
if config is None: config = {}
|
||||
self.CART_WRITE_FNCPTR = cart_write_fncptr
|
||||
self.CART_WRITE_FAST_FNCPTR = cart_write_fast_fncptr
|
||||
self.CART_READ_FNCPTR = cart_read_fncptr
|
||||
self.CART_POWERCYCLE_FNCPTR = cart_powercycle_fncptr
|
||||
self.PROGRESS_FNCPTR = progress_fncptr
|
||||
self.SET_WE_PIN_WR = set_we_pin_wr
|
||||
self.SET_WE_PIN_AUDIO = set_we_pin_audio
|
||||
self.CONFIG = config
|
||||
if "command_set" in config:
|
||||
self.CONFIG["_command_set"] = config["command_set"]
|
||||
|
|
@ -33,6 +38,8 @@ class Flashcart:
|
|||
self.CONFIG["_command_set"] = "INTEL"
|
||||
else:
|
||||
self.CONFIG["_command_set"] = ""
|
||||
if "write_pin" in config:
|
||||
self.DEFAULT_WE = config["write_pin"]
|
||||
|
||||
def CartRead(self, address, length=0):
|
||||
if length == 0:
|
||||
|
|
@ -42,16 +49,16 @@ class Flashcart:
|
|||
length = 1
|
||||
return self.CART_READ_FNCPTR(address, length)
|
||||
|
||||
def CartWrite(self, commands, flashcart=True, sram=False):
|
||||
if "command_set" in self.CONFIG and self.CONFIG["command_set"] in ("GBMEMORY", "DMG-MBC5-32M-FLASH"): flashcart = False
|
||||
dprint(commands, flashcart, sram)
|
||||
if flashcart and not sram:
|
||||
def CartWrite(self, commands, fast_write=True, sram=False):
|
||||
if "command_set" in self.CONFIG and self.CONFIG["command_set"] in ("GBMEMORY", "DMG-MBC5-32M-FLASH"): fast_write = False
|
||||
dprint(commands, fast_write, sram)
|
||||
if fast_write and not sram:
|
||||
self.CART_WRITE_FAST_FNCPTR(commands, flashcart=True)
|
||||
else:
|
||||
for command in commands:
|
||||
address = command[0]
|
||||
value = command[1]
|
||||
self.CART_WRITE_FNCPTR(address, value, flashcart=flashcart, sram=sram)
|
||||
self.CART_WRITE_FNCPTR(address, value, flashcart=fast_write, sram=sram)
|
||||
|
||||
def GetCommandSetType(self):
|
||||
return self.CONFIG["_command_set"].upper()
|
||||
|
|
@ -158,7 +165,7 @@ class Flashcart:
|
|||
dprint("Reading 0x{:X} bytes from cartridge at 0x{:X} = {:s}".format(command[1], command[0], str(temp)))
|
||||
time.sleep(0.001)
|
||||
if "unlock" in self.CONFIG["commands"]:
|
||||
self.CartWrite(self.CONFIG["commands"]["unlock"])
|
||||
self.CartWrite(self.CONFIG["commands"]["unlock"], fast_write=False)
|
||||
time.sleep(0.001)
|
||||
|
||||
def Reset(self, full_reset=False, max_address=0x2000000):
|
||||
|
|
@ -172,7 +179,7 @@ class Flashcart:
|
|||
if j >= max_address: break
|
||||
dprint("reset_every @ 0x{:X}".format(j))
|
||||
for command in self.CONFIG["commands"]["reset"]:
|
||||
self.CartWrite([[j, command[1]]])
|
||||
self.CartWrite([[j + command[0], command[1]]])
|
||||
time.sleep(0.01)
|
||||
elif "reset" in self.CONFIG["commands"]:
|
||||
self.CartWrite(self.CONFIG["commands"]["reset"])
|
||||
|
|
@ -285,8 +292,23 @@ class Flashcart:
|
|||
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]
|
||||
if len(self.CONFIG["commands"]["chip_erase"][i]) > 2:
|
||||
we = self.CONFIG["commands"]["chip_erase"][i][2]
|
||||
else:
|
||||
we = None
|
||||
|
||||
if not addr == None:
|
||||
if we == "WR":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif we == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
self.CartWrite([[addr, data]])
|
||||
if we is not None:
|
||||
if self.DEFAULT_WE == "WR":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif self.DEFAULT_WE == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
|
||||
time.sleep(0.1)
|
||||
if self.CONFIG["commands"]["chip_erase_wait_for"][i][0] != None:
|
||||
addr = self.CONFIG["commands"]["chip_erase_wait_for"][i][0]
|
||||
|
|
@ -298,7 +320,18 @@ class Flashcart:
|
|||
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":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif we == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
self.CartWrite([[addr, sr_data]])
|
||||
if we is not None:
|
||||
if self.DEFAULT_WE == "WR":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif self.DEFAULT_WE == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
|
||||
self.CartRead(addr, 2) # dummy read (fixes some bootlegs)
|
||||
wait_for = struct.unpack("<H", self.CartRead(addr, 2))[0]
|
||||
self.LAST_SR = wait_for
|
||||
|
|
@ -320,13 +353,28 @@ class Flashcart:
|
|||
for i in range(0, len(self.CONFIG["commands"]["sector_erase"])):
|
||||
addr = self.CONFIG["commands"]["sector_erase"][i][0]
|
||||
data = self.CONFIG["commands"]["sector_erase"][i][1]
|
||||
if len(self.CONFIG["commands"]["sector_erase"][i]) > 2:
|
||||
we = self.CONFIG["commands"]["sector_erase"][i][2]
|
||||
else:
|
||||
we = None
|
||||
|
||||
if addr == "SA": addr = pos
|
||||
if addr == "SA+1": addr = pos + 1
|
||||
if addr == "SA+2": addr = pos + 2
|
||||
if addr == "SA+0x4000": addr = pos + 0x4000
|
||||
if addr == "SA+0x7000": addr = pos + 0x7000
|
||||
if not addr == None:
|
||||
if we == "WR":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif we == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
self.CartWrite([[addr, data]])
|
||||
if we is not None:
|
||||
if self.DEFAULT_WE == "WR":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif self.DEFAULT_WE == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
|
||||
if self.CONFIG["commands"]["sector_erase_wait_for"][i][0] != None:
|
||||
addr = self.CONFIG["commands"]["sector_erase_wait_for"][i][0]
|
||||
data = self.CONFIG["commands"]["sector_erase_wait_for"][i][1]
|
||||
|
|
@ -342,7 +390,18 @@ class Flashcart:
|
|||
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":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif we == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
self.CartWrite([[sr_addr, sr_data]])
|
||||
if we is not None:
|
||||
if self.DEFAULT_WE == "WR":
|
||||
self.SET_WE_PIN_WR()
|
||||
elif self.DEFAULT_WE == "AUDIO":
|
||||
self.SET_WE_PIN_AUDIO()
|
||||
|
||||
self.CartRead(addr, 2) # dummy read (fixes some bootlegs)
|
||||
temp = self.CartRead(addr, 2)
|
||||
if len(temp) != 2:
|
||||
|
|
|
|||
|
|
@ -517,7 +517,7 @@ class DMG_MBC6(DMG_MBC):
|
|||
sr = self.CartRead(0x4000)
|
||||
dprint("Status Register Check: 0x{:X} == 0x80? {:s}".format(sr, str(sr == 0x80)))
|
||||
if sr == 0x80: break
|
||||
time.sleep(0.0001)
|
||||
time.sleep(0.01)
|
||||
|
||||
def GetFlashID(self):
|
||||
self.EnableFlash(enable=True)
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ from enum import Enum
|
|||
|
||||
# Common constants
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "3.20"
|
||||
VERSION_PEP440 = "3.21"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
DEBUG = False
|
||||
DEBUG_LOG = []
|
||||
|
|
@ -21,7 +21,7 @@ AGB_Flash_Save_Chips = { 0xBFD4:"SST 39VF512", 0x1F3D:"Atmel AT29LV512", 0xC21C:
|
|||
AGB_Flash_Save_Chips_Sizes = [ 0x10000, 0x10000, 0x10000, 0x10000, 0x20000, 0x20000 ]
|
||||
|
||||
DMG_Header_Mapper = { 0x00:'None', 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY', 0x06:'MBC2+SRAM+BATTERY', 0x10:'MBC3+RTC+SRAM+BATTERY', 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:'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 ], "MBC1":[ 0x01, 0x02, 0x03 ], "MBC2":[ 0x06 ], "MBC3":[ 0x10, 0x13 ], "MBC5":[ 0x19, 0x1B, 0x1C, 0x1E ], "MBC6":[ 0x20 ], "MBC7":[ 0x22 ], "MBC1M":[ 0x101, 0x103 ], "MMM01":[ 0x0B, 0x0D ], "GBD":[ 0xFC ], "G-MMC1":[ 0x105 ], "M161":[ 0x104 ], "HuC-1":[ 0xFF ], "HuC-3":[ 0xFE ], "TAMA5":[ 0xFD ], "256M Multi Cart":[ 0x201 ], "Wisdom Tree":[ 0x202 ], "Xploder GB":[ 0x203 ], "Sachen":[ 0x204 ], "Datel Orbit V2":[ 0x205 ] }
|
||||
DMG_Mapper_Types = { "None":[ 0x00 ], "MBC1":[ 0x01, 0x02, 0x03 ], "MBC2":[ 0x06 ], "MBC3":[ 0x10, 0x13 ], "MBC5":[ 0x19, 0x1A, 0x1B, 0x1C, 0x1E ], "MBC6":[ 0x20 ], "MBC7":[ 0x22 ], "MBC1M":[ 0x101, 0x103 ], "MMM01":[ 0x0B, 0x0D ], "GBD":[ 0xFC ], "G-MMC1":[ 0x105 ], "M161":[ 0x104 ], "HuC-1":[ 0xFF ], "HuC-3":[ 0xFE ], "TAMA5":[ 0xFD ], "256M Multi Cart":[ 0x201 ], "Wisdom Tree":[ 0x202 ], "Xploder GB":[ 0x203 ], "Sachen":[ 0x204 ], "Datel Orbit V2":[ 0x205 ] }
|
||||
DMG_Header_ROM_Sizes = [ "32 KB", "64 KB", "128 KB", "256 KB", "512 KB", "1 MB", "2 MB", "4 MB", "8 MB", "16 MB", "32 MB" ]
|
||||
DMG_Header_ROM_Sizes_Map = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A ]
|
||||
DMG_Header_ROM_Sizes_Flasher_Map = [ 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000 ]
|
||||
|
|
|
|||
|
|
@ -20222,11 +20222,32 @@
|
|||
"st": 3,
|
||||
"gc": "RZWJ"
|
||||
},
|
||||
"1b58262c2bea83608faeb85db1ef1d9423b09b1b": {
|
||||
"rc": 3149310304,
|
||||
"rs": 2097152,
|
||||
"ss": 512,
|
||||
"st": 1,
|
||||
"gc": "TCHK"
|
||||
},
|
||||
"569244c74f0f1c6d9bc1efefb6a2a1d0a5bdd77b": {
|
||||
"rc": 3494379487,
|
||||
"rs": 8388608,
|
||||
"ss": 0,
|
||||
"st": 0,
|
||||
"ss": 512,
|
||||
"st": 1,
|
||||
"gc": "TCHK"
|
||||
},
|
||||
"5dd63ac864ec954cb3ed58a51b34bec1eaa17cda": {
|
||||
"rc": 778659949,
|
||||
"rs": 2097152,
|
||||
"ss": 512,
|
||||
"st": 1,
|
||||
"gc": "TCHK"
|
||||
},
|
||||
"72ba2ff35d246d36482381588b80c8b2cddae76f": {
|
||||
"rc": 2528463141,
|
||||
"rs": 1326620,
|
||||
"ss": 512,
|
||||
"st": 1,
|
||||
"gc": "TCHK"
|
||||
},
|
||||
"3fc931b3150d91bca7b4d525fc2894814d51a08c": {
|
||||
|
|
|
|||
56
FlashGBX/config/fc_AGB_AR_SST39VF800A.txt
Normal file
56
FlashGBX/config/fc_AGB_AR_SST39VF800A.txt
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"Action Replay Ultimate Codes (SST39VF800A)"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xBF, 0x00, 0x81, 0x27 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x100000,
|
||||
"chip_erase_timeout":10,
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0xAAAA, 0xAA ],
|
||||
[ 0x5555, 0x55 ],
|
||||
[ 0xAAAA, 0x90 ]
|
||||
],
|
||||
"read_cfi":[
|
||||
[ 0xAAAA, 0xAA ],
|
||||
[ 0x5555, 0x55 ],
|
||||
[ 0xAAAA, 0x98 ]
|
||||
],
|
||||
"chip_erase":[
|
||||
[ 0xAAAA, 0xAA ],
|
||||
[ 0x5555, 0x55 ],
|
||||
[ 0xAAAA, 0x80 ],
|
||||
[ 0xAAAA, 0xAA ],
|
||||
[ 0x5555, 0x55 ],
|
||||
[ 0xAAAA, 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":[
|
||||
[ 0xAAAA, 0xAA ],
|
||||
[ 0x5555, 0x55 ],
|
||||
[ 0xAAAA, 0xA0 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -14,15 +14,7 @@
|
|||
"commands":{
|
||||
"unlock":[
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x1234, 5 ],
|
||||
[ 0x000ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5678, 5 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x0ECA800, 0x5678, 1 ],
|
||||
[ 0x00268A0, 0x1234, 1 ],
|
||||
[ 0x002468A, 0xABCD, 5 ],
|
||||
[ 0x1C2468A, 0xA55A, 1 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x1E2468A, 0x9413, 1 ]
|
||||
],
|
||||
|
|
|
|||
|
|
@ -14,15 +14,7 @@
|
|||
"commands":{
|
||||
"unlock":[
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x1234, 5 ],
|
||||
[ 0x000ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5678, 5 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x0ECA800, 0x5678, 1 ],
|
||||
[ 0x00268A0, 0x1234, 1 ],
|
||||
[ 0x002468A, 0xABCD, 5 ],
|
||||
[ 0x1C2468A, 0xA55A, 1 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x1E2468A, 0x9413, 1 ]
|
||||
],
|
||||
|
|
|
|||
73
FlashGBX/config/fc_AGB_Flash2Advance_Ultra_256M.txt
Normal file
73
FlashGBX/config/fc_AGB_Flash2Advance_Ultra_256M.txt
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"Flash2Advance Ultra 256M with 8× 3204C3B100"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x89, 0x00, 0x89, 0x00, 0xC5, 0x88, 0xC5, 0x88 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
"sector_size":[
|
||||
[0x04000, 8],
|
||||
[0x20000, 63],
|
||||
[0x04000, 8],
|
||||
[0x20000, 63],
|
||||
[0x04000, 8],
|
||||
[0x20000, 63],
|
||||
[0x04000, 8],
|
||||
[0x20000, 63]
|
||||
],
|
||||
"reset_every":0x800000,
|
||||
"command_set":"INTEL",
|
||||
"commands":{
|
||||
"unlock":[
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x1C2468A, 0xA55A, 1 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x1E2468A, 0x9413, 1 ]
|
||||
],
|
||||
"reset":[
|
||||
[ 0, 0xFF ],
|
||||
[ 2, 0xFF ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0, 0x90 ],
|
||||
[ 2, 0x90 ]
|
||||
],
|
||||
"sector_erase":[
|
||||
[ "SA", 0x60 ],
|
||||
[ "SA", 0xD0 ],
|
||||
[ "SA", 0x20 ],
|
||||
[ "SA", 0xD0 ],
|
||||
[ "SA+2", 0x60 ],
|
||||
[ "SA+2", 0xD0 ],
|
||||
[ "SA+2", 0x20 ],
|
||||
[ "SA+2", 0xD0 ],
|
||||
[ null, null ],
|
||||
[ null, null ]
|
||||
],
|
||||
"sector_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 ],
|
||||
[ "SA", 0x80, 0xFFFF ],
|
||||
[ "SA+2", 0x80, 0xFFFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0, 0x70 ],
|
||||
[ 0, 0x10 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ 0, 0x80, 0x80 ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -16,15 +16,7 @@
|
|||
"commands":{
|
||||
"unlock":[
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x1234, 5 ],
|
||||
[ 0x000ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5678, 5 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x0ECA800, 0x5678, 1 ],
|
||||
[ 0x00268A0, 0x1234, 1 ],
|
||||
[ 0x002468A, 0xABCD, 5 ],
|
||||
[ 0x1C2468A, 0xA55A, 1 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x1E2468A, 0x9413, 1 ]
|
||||
],
|
||||
|
|
|
|||
|
|
@ -15,15 +15,7 @@
|
|||
"commands":{
|
||||
"unlock":[
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x1234, 5 ],
|
||||
[ 0x000ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5678, 5 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x002468A, 0x5354, 1 ],
|
||||
[ 0x0ECA800, 0x5678, 1 ],
|
||||
[ 0x00268A0, 0x1234, 1 ],
|
||||
[ 0x002468A, 0xABCD, 5 ],
|
||||
[ 0x1C2468A, 0xA55A, 1 ],
|
||||
[ 0x130ECA8, 0x5354, 1 ],
|
||||
[ 0x1E2468A, 0x9413, 1 ]
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,13 +4,15 @@
|
|||
"4455_4400_4000_4350_36L0R_V3 with M36L0R7050T",
|
||||
"4050_4400_4000_4350_36L0R_V5 with M36L0R7050T",
|
||||
"4050_4400_4000_4350_36L0R_6108 with M36L0R7050B",
|
||||
"4000L0ZBQ0 DRV with 3000L0YBQ0"
|
||||
"4000L0ZBQ0 DRV with 3000L0YBQ0",
|
||||
"F864-3 with M36L0R7050B"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x20, 0x00, 0xC4, 0x88 ],
|
||||
[ 0x20, 0x00, 0xC4, 0x88 ],
|
||||
[ 0x20, 0x00, 0xC6, 0x88 ],
|
||||
[ 0x8A, 0x00, 0x0F, 0x88 ]
|
||||
[ 0x8A, 0x00, 0x0F, 0x88 ],
|
||||
[ 0x20, 0x00, 0xC5, 0x88 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x1000000,
|
||||
|
|
|
|||
75
FlashGBX/config/fc_DMG_BV_MBC3000.txt
Normal file
75
FlashGBX/config/fc_DMG_BV_MBC3000.txt
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"BennVenn MBC3000 RTC cart"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xC2, 0xC2, 0xCB, 0xCB ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x800000,
|
||||
"start_addr":0,
|
||||
"first_bank":1,
|
||||
"write_pin":"WR",
|
||||
"sector_size_from_cfi":true,
|
||||
"chip_erase_timeout":200,
|
||||
"mbc":"manual",
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x90 ]
|
||||
],
|
||||
"read_cfi":[
|
||||
[ 0xAAA, 0x98 ]
|
||||
],
|
||||
"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, 0xFF, 0xFF ]
|
||||
],
|
||||
"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", 0xFF, 0xFF ]
|
||||
],
|
||||
"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 ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
"Catskull 32k Gameboy Flash Cart"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xBF, 0xB5, 0x01, 0xFF ]
|
||||
[ 0xBF, 0xB5 ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x8000,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
],
|
||||
"flash_ids":[
|
||||
[ 0xBF, 0xFF, 0x25, 0xFF ],
|
||||
[ 0xBF, 0xB7, 0xFF, 0xFF ]
|
||||
[ 0xBF, 0xB7 ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x8000,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
"Ferrante Crafts cart 64 KB"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xBF, 0xB5, 0x01, 0xFF ]
|
||||
[ 0xBF, 0xB5 ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x10000,
|
||||
|
|
|
|||
|
|
@ -5,14 +5,16 @@
|
|||
"SD007_TSOP_48BALL_V10 with M29W320DT",
|
||||
"SD007_TSOP_48BALL_V10 with GL032M10BFIR3",
|
||||
"SD007_TSOP_48BALL_V9 with 29LV320CBTC-70G",
|
||||
"SD007_TSOP_48BALL_V10 with 29DL32TF-70"
|
||||
"SD007_TSOP_48BALL_V10 with 29DL32TF-70",
|
||||
"SD007_48BALL_SOP28 with M29W320ET"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x02, 0x02, 0x7D, 0x7D ],
|
||||
[ 0x20, 0x20, 0xC9, 0xC9 ],
|
||||
[ 0x02, 0x02, 0x7D, 0x7D ],
|
||||
[ 0x02, 0x02, 0x7D, 0x7D ],
|
||||
[ 0x04, 0x04, 0x7D, 0x7D ]
|
||||
[ 0x04, 0x04, 0x7D, 0x7D ],
|
||||
[ 0x20, 0x20, 0x55, 0x55 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"voltage_variants":true,
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"DIY cart with MBC3 and MX29LV640 @ AUDIO"
|
||||
"DIY cart with MX29LV640 @ AUDIO"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xC2, 0xC2, 0xCB, 0xCB ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"voltage_variants":true,
|
||||
"flash_size":0x800000,
|
||||
"start_addr":0,
|
||||
"first_bank":1,
|
||||
"mbc":0x13,
|
||||
"write_pin":"AUDIO",
|
||||
"sector_size_from_cfi":true,
|
||||
"chip_erase_timeout":200,
|
||||
"mbc":"manual",
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
|
|
@ -42,6 +44,22 @@
|
|||
[ null, null, null ],
|
||||
[ 0, 0xFF, 0xFF ]
|
||||
],
|
||||
"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", 0xFF, 0xFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
|
|
|
|||
76
FlashGBX/config/fc_DMG_MX29LV640_WR.txt
Normal file
76
FlashGBX/config/fc_DMG_MX29LV640_WR.txt
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"DIY cart with MX29LV640 @ WR"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xC2, 0xC2, 0xCB, 0xCB ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"voltage_variants":true,
|
||||
"flash_size":0x800000,
|
||||
"start_addr":0,
|
||||
"first_bank":1,
|
||||
"write_pin":"WR",
|
||||
"sector_size_from_cfi":true,
|
||||
"chip_erase_timeout":200,
|
||||
"mbc":"manual",
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0xAAA, 0xAA ],
|
||||
[ 0x555, 0x55 ],
|
||||
[ 0xAAA, 0x90 ]
|
||||
],
|
||||
"read_cfi":[
|
||||
[ 0xAAA, 0x98 ]
|
||||
],
|
||||
"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, 0xFF, 0xFF ]
|
||||
],
|
||||
"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", 0xFF, 0xFF ]
|
||||
],
|
||||
"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 ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
"Ferrante Crafts cart 512 KB"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xBF, 0xB7, 0x01, 0xFF ]
|
||||
[ 0xBF, 0xB7 ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x80000,
|
||||
|
|
|
|||
74
FlashGBX/config/fc_DMG_Squareboi_4MB_2x2.txt
Normal file
74
FlashGBX/config/fc_DMG_Squareboi_4MB_2x2.txt
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"Squareboi 4 MB (2× 2 MB)"
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x400000,
|
||||
"start_addr":0x4000,
|
||||
"first_bank":0,
|
||||
"write_pin":"AUDIO",
|
||||
"chip_erase_timeout":120,
|
||||
"mbc":0x1B,
|
||||
"command_set":"AMD",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0x4000, 0xF0 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0x4AAA, 0xAA ],
|
||||
[ 0x4555, 0x55 ],
|
||||
[ 0x4AAA, 0x90 ]
|
||||
],
|
||||
"read_cfi":[
|
||||
[ 0x4AAA, 0x98 ]
|
||||
],
|
||||
"chip_erase":[
|
||||
[ 0x2100, 0x00, "WR" ],
|
||||
[ 0x4AAA, 0xAA ],
|
||||
[ 0x4555, 0x55 ],
|
||||
[ 0x4AAA, 0x80 ],
|
||||
[ 0x4AAA, 0xAA ],
|
||||
[ 0x4555, 0x55 ],
|
||||
[ 0x4AAA, 0x10 ],
|
||||
[ 0x2100, 0x80, "WR" ],
|
||||
[ 0x4AAA, 0xAA ],
|
||||
[ 0x4555, 0x55 ],
|
||||
[ 0x4AAA, 0x80 ],
|
||||
[ 0x4AAA, 0xAA ],
|
||||
[ 0x4555, 0x55 ],
|
||||
[ 0x4AAA, 0x10 ],
|
||||
[ 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 ],
|
||||
[ 0x4000, 0xFF, 0xFF ],
|
||||
[ 0x4000, 0xFF, 0xFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ 0x4AAA, 0xAA ],
|
||||
[ 0x4555, 0x55 ],
|
||||
[ 0x4AAA, 0xA0 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,14 @@
|
|||
{
|
||||
"type":"DMG",
|
||||
"names":[
|
||||
"SD007_T40_64BALL_TSOP28 with TC58FVB016FT-85"
|
||||
"SD007_T40_64BALL_TSOP28 with TC58FVB016FT-85",
|
||||
"SD007_T40_64BALL_S71_TV_TS28 with TC58FVB016FT-85",
|
||||
"SD007_T40_64BALL_SOJ28 with 29LV016T"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x98, 0x45, 0x00, 0x2A ]
|
||||
[ 0x98, 0x45, 0x00, 0x2A ],
|
||||
[ 0x98, 0x45, 0x00, 0x2A ],
|
||||
[ 0x04, 0xC7, 0x00, 0x00 ]
|
||||
],
|
||||
"voltage":5,
|
||||
"flash_size":0x200000,
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ class FirmwareUpdaterWindow(QtWidgets.QDialog):
|
|||
self.reject()
|
||||
return True
|
||||
elif ret == 2:
|
||||
text = "The firmware update is has failed. Please try again."
|
||||
text = "The firmware update has failed. Please try again."
|
||||
self.btnUpdate.setEnabled(True)
|
||||
self.btnClose.setEnabled(True)
|
||||
self.optDevicePCBVer14.setEnabled(True)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class GbxDevice:
|
|||
DEVICE_NAME = "GBxCart RW"
|
||||
DEVICE_MIN_FW = 1
|
||||
DEVICE_MAX_FW = 8
|
||||
DEVICE_LATEST_FW_TS = { 4:1619427330, 5:1669112674, 6:1669112674 }
|
||||
DEVICE_LATEST_FW_TS = { 4:1619427330, 5:1673788742, 6:1673788742 }
|
||||
|
||||
DEVICE_CMD = {
|
||||
"NULL":0x30,
|
||||
|
|
@ -113,7 +113,9 @@ class GbxDevice:
|
|||
FAST_READ = False
|
||||
SKIPPING = False
|
||||
BAUDRATE = 1000000
|
||||
MAX_BUFFER_LEN = 512
|
||||
MAX_BUFFER_LEN = 0x2000
|
||||
DEVICE_TIMEOUT = 1
|
||||
WRITE_DELAY = False
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
|
@ -140,18 +142,21 @@ class GbxDevice:
|
|||
if not self.LoadFirmwareVersion() and max_baud >= 1700000:
|
||||
dev.close()
|
||||
self.BAUDRATE = 1700000
|
||||
self.MAX_BUFFER_LEN = 0x2000
|
||||
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
||||
self.DEVICE = dev
|
||||
if not self.LoadFirmwareVersion():
|
||||
dev.close()
|
||||
self.DEVICE = None
|
||||
self.BAUDRATE = 1000000
|
||||
self.MAX_BUFFER_LEN = 0x100
|
||||
continue
|
||||
elif max_baud >= 1700000 and self.FW["pcb_ver"] in (5, 6, 101) and self.BAUDRATE < 1700000:
|
||||
# Switch to higher baud rate
|
||||
self._write(self.DEVICE_CMD["OFW_USART_1_7M_SPEED"])
|
||||
self.BAUDRATE = 1700000
|
||||
dev.close()
|
||||
#self._write(self.DEVICE_CMD["OFW_USART_1_7M_SPEED"])
|
||||
#self.BAUDRATE = 1700000
|
||||
#dev.close()
|
||||
self.ChangeBaudRate(baudrate=1700000)
|
||||
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
||||
self.DEVICE = dev
|
||||
|
||||
|
|
@ -186,7 +191,7 @@ class GbxDevice:
|
|||
conn_msg.append([0, "For help please visit the insideGadgets Discord: https://gbxcart.com/discord"])
|
||||
|
||||
self.PORT = ports[i]
|
||||
self.DEVICE.timeout = 1
|
||||
self.DEVICE.timeout = self.DEVICE_TIMEOUT
|
||||
|
||||
# Load Flash Cartridge Handlers
|
||||
self.UpdateFlashCarts(flashcarts)
|
||||
|
|
@ -242,6 +247,19 @@ class GbxDevice:
|
|||
def GetBaudRate(self):
|
||||
return self.BAUDRATE
|
||||
|
||||
def ChangeBaudRate(self, baudrate):
|
||||
if not self.IsConnected(): return
|
||||
if baudrate == 1700000:
|
||||
self._write(self.DEVICE_CMD["OFW_USART_1_7M_SPEED"])
|
||||
self.Close()
|
||||
self.BAUDRATE = baudrate
|
||||
self.MAX_BUFFER_LEN = 0x2000
|
||||
elif baudrate == 1000000:
|
||||
self._write(self.DEVICE_CMD["OFW_USART_1_0M_SPEED"])
|
||||
self.Close()
|
||||
self.BAUDRATE = baudrate
|
||||
self.MAX_BUFFER_LEN = 0x100
|
||||
|
||||
def CanSetVoltageManually(self):
|
||||
return False
|
||||
|
||||
|
|
@ -381,6 +399,10 @@ class GbxDevice:
|
|||
def GetFWBuildDate(self):
|
||||
return self.FW["fw_dt"]
|
||||
|
||||
def SetWriteDelay(self, enable=True):
|
||||
dprint("Setting Write Delay to", enable)
|
||||
self.WRITE_DELAY = enable
|
||||
|
||||
def wait_for_ack(self, values=None):
|
||||
if values is None: values = [0x01, 0x03]
|
||||
buffer = self._read(1)
|
||||
|
|
@ -396,10 +418,10 @@ class GbxDevice:
|
|||
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))
|
||||
#print(self.CANCEL_ARGS)
|
||||
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
|
||||
self.SetWriteDelay(enable=True)
|
||||
return False
|
||||
|
||||
return buffer
|
||||
|
|
@ -417,7 +439,7 @@ class GbxDevice:
|
|||
# On MacOS it’s possible not all bytes are transmitted successfully,
|
||||
# even though we’re using flush() which is the tcdrain function.
|
||||
# Still looking for a better solution than delaying here.
|
||||
if platform.system() == "Darwin":
|
||||
if platform.system() == "Darwin" or self.WRITE_DELAY is True:
|
||||
time.sleep(0.00125)
|
||||
|
||||
if wait: return self.wait_for_ack()
|
||||
|
|
@ -541,6 +563,7 @@ class GbxDevice:
|
|||
self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"A critical communication error occured during a write. Please avoid passive USB hubs, try different USB ports/cables and re-connect the device."})
|
||||
self.CANCEL = True
|
||||
self.ERROR = True
|
||||
return False
|
||||
|
||||
def _clk_toggle(self, num):
|
||||
if self.FW["pcb_ver"] not in (5, 6, 101): return False
|
||||
|
|
@ -549,6 +572,13 @@ class GbxDevice:
|
|||
self._write(self.DEVICE_CMD["CLK_LOW"])
|
||||
return True
|
||||
|
||||
def _set_we_pin_wr(self):
|
||||
if self.MODE == "DMG":
|
||||
self._set_fw_variable("FLASH_WE_PIN", 0x01) # FLASH_WE_PIN_WR
|
||||
def _set_we_pin_audio(self):
|
||||
if self.MODE == "DMG":
|
||||
self._set_fw_variable("FLASH_WE_PIN", 0x02) # FLASH_WE_PIN_AUDIO
|
||||
|
||||
def CartPowerCycle(self, delay=0.1):
|
||||
if self.CanPowerCycleCart():
|
||||
dprint("Power cycling cartridge with a delay of {:.1f} seconds".format(delay))
|
||||
|
|
@ -1457,7 +1487,7 @@ class GbxDevice:
|
|||
elif we == "WR+RESET":
|
||||
self._set_fw_variable("FLASH_WE_PIN", 0x03) # FLASH_WE_PIN_WR_RESET
|
||||
|
||||
flashcart = Flashcart(config=flashcart_meta, cart_write_fncptr=self._cart_write, cart_write_fast_fncptr=self._cart_write_flash, cart_read_fncptr=self.ReadROM, cart_powercycle_fncptr=self.CartPowerCycle)
|
||||
flashcart = Flashcart(config=flashcart_meta, cart_write_fncptr=self._cart_write, cart_write_fast_fncptr=self._cart_write_flash, cart_read_fncptr=self.ReadROM, cart_powercycle_fncptr=self.CartPowerCycle, set_we_pin_wr=self._set_we_pin_wr, set_we_pin_audio=self._set_we_pin_audio)
|
||||
flashcart.Reset(full_reset=False)
|
||||
if flashcart.Unlock() is False: return False
|
||||
if "flash_ids" in flashcart_meta and len(flashcart_meta["flash_ids"]) > 0:
|
||||
|
|
@ -1501,7 +1531,24 @@ class GbxDevice:
|
|||
flash_type_id = flash_types[i]
|
||||
size_undetected = False
|
||||
break
|
||||
|
||||
else:
|
||||
if self.MODE == "AGB":
|
||||
# Check where the ROM data repeats (for unlicensed carts)
|
||||
header = self.ReadROM(0, 0x180)
|
||||
size_check = header[0xA0:0xA0+16]
|
||||
currAddr = 0x10000
|
||||
while currAddr < 0x2000000:
|
||||
buffer = self.ReadROM(currAddr + 0xA0, 64)[:16]
|
||||
if buffer == size_check: break
|
||||
currAddr *= 2
|
||||
rom_size = currAddr
|
||||
|
||||
for i in range(0, len(flash_types)):
|
||||
if "flash_size" in supp_flash_types[1][flash_types[i]] and rom_size == supp_flash_types[1][flash_types[i]]["flash_size"]:
|
||||
flash_type_id = flash_types[i]
|
||||
size_undetected = False
|
||||
break
|
||||
|
||||
else:
|
||||
(flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage)
|
||||
|
||||
|
|
@ -1667,7 +1714,7 @@ class GbxDevice:
|
|||
self._cart_write(method['reset'][i][0], method['reset'][i][1], flashcart=True)
|
||||
|
||||
if cart_type is not None: # reset cartridge if method is known
|
||||
flashcart = Flashcart(config=cart_type, 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=None)
|
||||
flashcart = Flashcart(config=cart_type, 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=None, set_we_pin_wr=self._set_we_pin_wr, set_we_pin_audio=self._set_we_pin_audio)
|
||||
flashcart.Reset(full_reset=False)
|
||||
|
||||
if "method" in cfi:
|
||||
|
|
@ -1737,7 +1784,7 @@ class GbxDevice:
|
|||
time.sleep(0.2)
|
||||
|
||||
if cart_type is not None: # reset cartridge if method is known
|
||||
flashcart = Flashcart(config=cart_type, 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=None)
|
||||
flashcart = Flashcart(config=cart_type, 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=None, set_we_pin_wr=self._set_we_pin_wr, set_we_pin_audio=self._set_we_pin_audio)
|
||||
flashcart.Reset(full_reset=True)
|
||||
|
||||
flash_id = ""
|
||||
|
|
@ -1792,7 +1839,7 @@ class GbxDevice:
|
|||
file = open(args["path"], "wb")
|
||||
|
||||
self.FAST_READ = True
|
||||
|
||||
|
||||
flashcart = False
|
||||
supported_carts = list(self.SUPPORTED_CARTS[self.MODE].values())
|
||||
cart_type = copy.deepcopy(supported_carts[args["cart_type"]])
|
||||
|
|
@ -1802,7 +1849,7 @@ class GbxDevice:
|
|||
if i == args["cart_type"]:
|
||||
try:
|
||||
cart_type["_index"] = cart_type["names"].index(list(self.SUPPORTED_CARTS[self.MODE].keys())[i])
|
||||
flashcart = Flashcart(config=cart_type, 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)
|
||||
flashcart = Flashcart(config=cart_type, 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)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
|
@ -1890,11 +1937,12 @@ class GbxDevice:
|
|||
|
||||
buffer = bytearray(size)
|
||||
max_length = self.MAX_BUFFER_LEN
|
||||
dprint("Max buffer size: 0x{:X}".format(max_length))
|
||||
if self.FAST_READ is True:
|
||||
if (self.MODE == "AGB" and "command_set" in cart_type and cart_type["command_set"] == "3DMEMORY"):
|
||||
max_length = 0x1000
|
||||
max_length = min(max_length, 0x1000)
|
||||
else:
|
||||
max_length = 0x2000
|
||||
max_length = min(max_length, 0x2000)
|
||||
self.INFO["dump_info"]["transfer_size"] = max_length
|
||||
pos_total = 0
|
||||
start_address = 0
|
||||
|
|
@ -1968,21 +2016,31 @@ class GbxDevice:
|
|||
skip_init = True
|
||||
|
||||
if len(temp) != buffer_len:
|
||||
if "verify_write" in args:
|
||||
self.SetProgress({"action":"UPDATE_POS", "pos":args["verify_from"]+pos_total})
|
||||
else:
|
||||
self.SetProgress({"action":"UPDATE_POS", "pos":pos_total})
|
||||
|
||||
if (max_length >> 1) < 64:
|
||||
dprint("Received 0x{:X} bytes instead of 0x{:X} bytes from the device at position 0x{:X}!".format(len(temp), buffer_len, pos_total))
|
||||
max_length = 64
|
||||
elif lives > 18:
|
||||
dprint("Received 0x{:X} bytes instead of 0x{:X} bytes from the device at position 0x{:X}!".format(len(temp), buffer_len, pos_total))
|
||||
else:
|
||||
dprint("Received 0x{:X} bytes instead of 0x{:X} bytes from the device at position 0x{:X}! Decreasing maximum transfer buffer length to 0x{:X}.".format(len(temp), buffer_len, pos_total, max_length >> 1))
|
||||
dprint("Received 0x{:X} bytes instead of 0x{:X} bytes from the device at position 0x{:X}! Decreasing maximum transfer buffer size to 0x{:X}.".format(len(temp), buffer_len, pos_total, max_length >> 1))
|
||||
max_length >>= 1
|
||||
self.MAX_BUFFER_LEN = max_length
|
||||
|
||||
self.INFO["dump_info"]["transfer_size"] = max_length
|
||||
skip_init = False
|
||||
self.DEVICE.reset_input_buffer()
|
||||
self.DEVICE.reset_output_buffer()
|
||||
lives -= 1
|
||||
if lives == 0:
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"An error occured while reading from the cartridge. When connecting the device, avoid passive USB hubs and try different USB ports/cables.", "abortable":False})
|
||||
return False
|
||||
self.CANCEL_ARGS.update({"info_type":"msgbox_critical", "info_msg":"An error occured while reading from the cartridge. When connecting the device, avoid passive USB hubs and try different USB ports/cables."})
|
||||
self.CANCEL = True
|
||||
self.ERROR = True
|
||||
if "verify_write" in args: return False
|
||||
continue
|
||||
elif lives < 20:
|
||||
lives = 20
|
||||
|
|
@ -1992,8 +2050,12 @@ class GbxDevice:
|
|||
pos_total += len(temp)
|
||||
|
||||
if "verify_write" in args:
|
||||
if pos_total >= len(args["verify_write"]): break
|
||||
#if pos_total >= len(args["verify_write"]): break
|
||||
check = args["verify_write"][pos_total-len(temp):pos_total]
|
||||
if Util.DEBUG:
|
||||
dprint("Writing 0x{:X} bytes to debug_verify.bin".format(len(temp)))
|
||||
with open("debug_verify.bin", "ab") as f: f.write(temp)
|
||||
|
||||
if temp[:len(check)] != check:
|
||||
for i in range(0, pos_total):
|
||||
if (i < len(args["verify_write"]) - 1) and (i < pos_total - 1) and args["verify_write"][i] != buffer[i]:
|
||||
|
|
@ -2001,11 +2063,9 @@ class GbxDevice:
|
|||
dprint("Skipping RTC area at 0x{:X}".format(i))
|
||||
else:
|
||||
dprint("Mismatch during verification at 0x{:X}".format(i))
|
||||
if Util.DEBUG:
|
||||
with open("debug_verify.bin", "wb") as f: f.write(temp)
|
||||
return i
|
||||
else:
|
||||
dprint("Verification successful between 0x{:X} and 0x{:X}".format(pos_total-len(temp), pos_total-1))
|
||||
dprint("Verification successful between 0x{:X} and 0x{:X}".format(pos_total-len(temp), pos_total))
|
||||
self.SetProgress({"action":"UPDATE_POS", "pos":args["verify_from"]+pos_total})
|
||||
else:
|
||||
self.SetProgress({"action":"UPDATE_POS", "pos":pos_total})
|
||||
|
|
@ -2644,7 +2704,7 @@ class GbxDevice:
|
|||
data_map_import = bytearray(data_map_import)
|
||||
dprint("Hidden sector data loaded")
|
||||
else:
|
||||
flashcart = Flashcart(config=cart_type, 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)
|
||||
flashcart = Flashcart(config=cart_type, 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)
|
||||
|
||||
rumble = "rumble" in flashcart.CONFIG and flashcart.CONFIG["rumble"] is True
|
||||
|
||||
|
|
@ -2882,7 +2942,7 @@ class GbxDevice:
|
|||
sector_offsets = flashcart.GetSectorOffsets(rom_size=len(data_import), rom_bank_size=rom_bank_size)
|
||||
if len(sector_offsets) > 0:
|
||||
flash_capacity = sector_offsets[-1][0] + sector_offsets[-1][1]
|
||||
if flash_capacity < len(data_import):
|
||||
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(flash_capacity, asInt=False)), "abortable":False})
|
||||
return False
|
||||
|
||||
|
|
@ -3131,10 +3191,12 @@ class GbxDevice:
|
|||
time.sleep(delay)
|
||||
self.CartPowerOn()
|
||||
if self.MODE == "DMG" and _mbc.HasFlashBanks(): _mbc.SelectBankFlash(bank)
|
||||
else:
|
||||
time.sleep(delay)
|
||||
time.sleep(delay)
|
||||
self.DEVICE.reset_input_buffer()
|
||||
self.DEVICE.reset_output_buffer()
|
||||
self._cart_write(pos, 0xF0)
|
||||
self._cart_write(pos, 0xFF)
|
||||
flashcart.Unlock()
|
||||
continue
|
||||
|
||||
self.CANCEL = True
|
||||
|
|
@ -3178,6 +3240,8 @@ class GbxDevice:
|
|||
verified = False
|
||||
if "verify_write" in args and args["verify_write"] is True:
|
||||
self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE_VERIFY", "size":len(data_import)})
|
||||
if Util.DEBUG:
|
||||
with open("debug_verify.bin", "wb") as f: pass
|
||||
for sector in write_sectors:
|
||||
verified = True
|
||||
if sector[0] >= len(data_import): break
|
||||
|
|
@ -3192,8 +3256,8 @@ class GbxDevice:
|
|||
end_address = buffer_pos
|
||||
|
||||
verified_size = self._BackupROM(verify_args)
|
||||
if verified_size is not None: dprint("args[\"verify_len\"]=0x{:X}, verified_size=0x{:X}".format(verify_args["verify_len"], verified_size))
|
||||
if self.CANCEL:
|
||||
if isinstance(verified_size, int): dprint("args[\"verify_len\"]=0x{:X}, verified_size=0x{:X}".format(verify_args["verify_len"], verified_size))
|
||||
if self.CANCEL or self.ERROR:
|
||||
cancel_args = {"action":"ABORT", "abortable":False}
|
||||
cancel_args.update(self.CANCEL_ARGS)
|
||||
self.CANCEL_ARGS = {}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
# This code is used for official firmware of GBxCart v1.3 only and this code is pure chaos, sorry
|
||||
# Refer to hw_GBxCartRW.py for the much cleaner rewrite (used for GBxCart RW v1.4 and firmware L1 on v1.3)
|
||||
|
||||
import time, math, struct, traceback, zlib, copy, hashlib, os, datetime
|
||||
import time, math, struct, traceback, zlib, copy, hashlib, os, datetime, platform
|
||||
import serial, serial.tools.list_ports
|
||||
from serial import SerialException
|
||||
from .RomFileDMG import RomFileDMG
|
||||
|
|
@ -139,6 +139,7 @@ class GbxDevice:
|
|||
NO_PROG_UPDATE = False
|
||||
FAST_READ = False
|
||||
BAUDRATE = 1000000
|
||||
WRITE_DELAY = False
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
|
@ -281,6 +282,9 @@ class GbxDevice:
|
|||
def GetBaudRate(self):
|
||||
return self.BAUDRATE
|
||||
|
||||
def ChangeBaudRate(self, _):
|
||||
return
|
||||
|
||||
def GetPCBVersion(self):
|
||||
_, pcb = self.FW
|
||||
if pcb in self.PCB_VERSIONS:
|
||||
|
|
@ -407,6 +411,9 @@ class GbxDevice:
|
|||
if args["action"] == "FINISHED":
|
||||
self.SIGNAL = None
|
||||
|
||||
def SetWriteDelay(self, enable=True):
|
||||
self.WRITE_DELAY = enable
|
||||
|
||||
def wait_for_ack(self):
|
||||
buffer = self.read(1)
|
||||
if buffer == False:
|
||||
|
|
@ -473,8 +480,9 @@ class GbxDevice:
|
|||
data = bytearray(data, 'ascii')
|
||||
self.DEVICE.write(data)
|
||||
self.DEVICE.flush()
|
||||
if wait_for_ack:
|
||||
return self.wait_for_ack()
|
||||
if platform.system() == "Darwin" or self.WRITE_DELAY is True:
|
||||
time.sleep(0.00125)
|
||||
if wait_for_ack: return self.wait_for_ack()
|
||||
|
||||
def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=False):
|
||||
self.SIGNAL = None
|
||||
|
|
@ -2498,7 +2506,6 @@ class GbxDevice:
|
|||
pos += 64
|
||||
|
||||
else: # super slow -- for testing purposes only!
|
||||
#self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Buffer writing for this flash chip is not supported with your device’s firmware version. You can try a newer firmware version which is available through the firmware updater in the “Tools” menu.\n\n{:s}".format(str(flashcart_meta["commands"]["buffer_write"])), "abortable":False})
|
||||
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please try a differnt firmware version or newer hardware revision.".format(APPNAME, self.GetFullName()), "abortable":False})
|
||||
return False
|
||||
'''
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
23
README.md
23
README.md
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
for [Windows](https://github.com/lesserkuma/FlashGBX/releases), [Linux](https://github.com/lesserkuma/FlashGBX#run-using-python-linux-macos-windows), [macOS](https://github.com/lesserkuma/FlashGBX#run-using-python-linux-macos-windows)
|
||||
|
||||
<img src="https://raw.githubusercontent.com/lesserkuma/FlashGBX/master/.github/01.png" alt="FlashGBX on Windows" width="400"><br><img src="https://raw.githubusercontent.com/lesserkuma/FlashGBX/master/.github/02.png" alt="GB Camera Album Viewer" width="400">
|
||||
<img src="https://raw.githubusercontent.com/lesserkuma/FlashGBX/master/.github/01.png" alt="FlashGBX on Windows 11" width="500"><br><img src="https://raw.githubusercontent.com/lesserkuma/FlashGBX/master/.github/02.png" alt="GB Camera Album Viewer" width="500">
|
||||
|
||||
## Introduction
|
||||
|
||||
|
|
@ -53,6 +53,8 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
|
||||
*FlashGBX should work on pretty much any operating system that supports Qt-GUI applications built using [Python](https://www.python.org/downloads/) with [PySide2](https://pypi.org/project/PySide2/) or [PySide6](https://pypi.org/project/PySide6/), [pyserial](https://pypi.org/project/pyserial/), [Pillow](https://pypi.org/project/Pillow/), [setuptools](https://pypi.org/project/setuptools/), [requests](https://pypi.org/project/requests/) and [python-dateutil](https://pypi.org/project/python-dateutil/) packages. To run FlashGBX in portable mode without installing, you can also download the source code archive and call `python3 run.py` after installing the prerequisites yourself.*
|
||||
|
||||
*Note: On Linux systems, the `brltty` module may render GBxCart RW devices non-accessible. See the troubleshooting section for details.*
|
||||
|
||||
#### Upgrading from an older version
|
||||
|
||||
1. Open a Terminal or Command Prompt window
|
||||
|
|
@ -93,6 +95,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- Game Boy
|
||||
|
||||
- 29LV Series Flash BOY with 29LV160DB
|
||||
- BennVenn MBC3000 RTC cart
|
||||
- BLAZE Xploder GB
|
||||
- BUNG Doctor GB Card 64M
|
||||
- Catskull 32k Gameboy Flash Cart
|
||||
|
|
@ -124,15 +127,18 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- insideGadgets 4 MB, 32 KB FRAM, MBC3+RTC
|
||||
- insideGadgets 4 MB (2× 2 MB), 32 KB FRAM, MBC5
|
||||
- Mr Flash 64M
|
||||
- Squareboi 4 MB (2× 2 MB)
|
||||
|
||||
- Game Boy Advance
|
||||
|
||||
- Action Replay Ultimate Codes (with SST39VF800A)
|
||||
- Development AGB Cartridge 64M Flash S, E201843
|
||||
- Development AGB Cartridge 128M Flash S, E201850
|
||||
- Development AGB Cartridge 256M Flash S, E201868
|
||||
- Flash2Advance 128M (with 2× 28F640J3A120)
|
||||
- Flash2Advance 256M (with 2× 28F128J3A150)
|
||||
- Flash2Advance Ultra 64M (with 2× 28F320C3B)
|
||||
- Flash2Advance Ultra 256M (with 8× 3204C3B100)
|
||||
- Flash Advance Card 64M (with 28F640J3A120)
|
||||
- insideGadgets 16 MB, 64K EEPROM with Solar Sensor and RTC options
|
||||
- insideGadgets 32 MB, 1M FLASH with RTC option
|
||||
|
|
@ -164,6 +170,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- SD007_48BALL_64M_V6 with 36VF3204
|
||||
- SD007_48BALL_64M_V6 with 29DL163BD-90
|
||||
- SD007_48BALL_64M_V8 with M29W160ET
|
||||
- SD007_48BALL_SOP28 with M29W320ET
|
||||
- SD007_BV5 with 29LV160TE-70PFTN
|
||||
- SD007_BV5_DRV with M29W320DT
|
||||
- SD007_BV5_DRV with S29GL032M90TFIR4
|
||||
|
|
@ -173,6 +180,8 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- SD007_BV5_V3 with HY29LV160BT-70
|
||||
- SD007_BV5_V3 with AM29LV160MB
|
||||
- SD007_K8D3216_32M with MX29LV160CT
|
||||
- SD007_T40_64BALL_S71_TV_TS28 with TC58FVB016FT-85
|
||||
- SD007_T40_64BALL_SOJ28 with 29LV016T
|
||||
- SD007_T40_64BALL_TSOP28 with 29LV016T
|
||||
- SD007_T40_64BALL_TSOP28 with TC58FVB016FT-85¹
|
||||
- SD007_TSOP_29LV017D with L017D70VC
|
||||
|
|
@ -245,6 +254,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- BX2006_TSOPBGA_0106 with K8D6316UTM-PI07
|
||||
- BX2006_TSOPBGA_6108 with M29W640
|
||||
- DV15 with MSP55LV100G
|
||||
- F864-3 with M36L0R7050B
|
||||
- GA-07 with unlabeled flash chip
|
||||
- GE28F128W30 with 128W30B0
|
||||
- M5M29G130AN (no PCB text)
|
||||
|
|
@ -272,6 +282,8 @@ Many different reproduction cartridges share their flash chip command set, so ev
|
|||
|
||||
* On some Linux systems like Fedora, you may need to install the `python3-pillow-qt` package manually in order for the GUI mode to work.
|
||||
|
||||
* On some Linux systems you may see the message “No devices found.” even though you’re using a USB cable capable of data transfers. This may be caused by a module called `brltty` (a driver for refreshable braille displays) that is erroneously interfering and taking over control of any connected USB device that uses the CH340/341 chipset. The solution would be to uninstall or blacklist the `brltty` driver and then reboot the system.
|
||||
|
||||
* If you’re using macOS version 10.13 or older, there may be no driver for the *insideGadgets GBxCart RW* device installed on your system. You can either upgrade your macOS version to 10.14+ or manually install a driver which is available [here](https://github.com/adrianmihalko/ch340g-ch34g-ch34x-mac-os-x-driver).
|
||||
|
||||
## Miscellaneous
|
||||
|
|
@ -285,6 +297,7 @@ The author would like to thank the following very kind people for their help and
|
|||
- 2358 (bug reports)
|
||||
- 90sFlav (flash chip info)
|
||||
- AcoVanConis (bug reports, flash chip info)
|
||||
- ALXCO-Hardware (feature suggestions)
|
||||
- AdmirtheSableye (bug reports)
|
||||
- AlexiG (GBxCart RW hardware, bug reports, flash chip info)
|
||||
- AndehX (app icon, flash chip info)
|
||||
|
|
@ -297,11 +310,12 @@ The author would like to thank the following very kind people for their help and
|
|||
- Davidish (flash chip info)
|
||||
- DevDavisNunez (bug reports)
|
||||
- Diddy_Kong (sample cartridge contribution)
|
||||
- djedditt (testing)
|
||||
- djedditt (testing, sample cartridge contribution)
|
||||
- Dr-InSide (bug reports)
|
||||
- dyf2007 (flash chip info)
|
||||
- easthighNerd (feature suggestions)
|
||||
- EchelonPrime (flash chip info)
|
||||
- edo999 (flash chip info)
|
||||
- EmperorOfTigers (bug reports, flash chip info)
|
||||
- endrift (research, mGBA emulator)
|
||||
- ethanstrax (flash chip info)
|
||||
|
|
@ -310,6 +324,7 @@ The author would like to thank the following very kind people for their help and
|
|||
- FerrantePescara (flash chip info)
|
||||
- frarees (bug reports)
|
||||
- Frost Clock (flash chip info)
|
||||
- gboh (bug reports)
|
||||
- gekkio (bug reports, technical information)
|
||||
- Godan (flash chip info)
|
||||
- Grender (testing)
|
||||
|
|
@ -335,7 +350,7 @@ The author would like to thank the following very kind people for their help and
|
|||
- manuelcm1 (flash chip info)
|
||||
- marv17 (flash chip info, testing, bug reports, feature suggestions)
|
||||
- Mr_V (flash chip info, testing)
|
||||
- orangeglo (GB Memory Cartridge samples)
|
||||
- orangeglo (GB Memory Cartridge samples, bug reports)
|
||||
- paarongiroux (bug reports)
|
||||
- Paradoxical (flash chip info)
|
||||
- Rairch (bug reports)
|
||||
|
|
@ -343,12 +358,14 @@ The author would like to thank the following very kind people for their help and
|
|||
- redalchemy (bug reports, flash chip info)
|
||||
- RetroGorek (flash chip info)
|
||||
- RevZ (Linux help, testing, bug reports, flash chip info)
|
||||
- s1cp (flash chip info)
|
||||
- Satumox (bug reports)
|
||||
- Sgt.DoudouMiel (flash chip info)
|
||||
- Shinichi999 (bug reports)
|
||||
- Sithdown (flash chip info)
|
||||
- skite2001 (flash chip info)
|
||||
- Smelly-Ghost (testing)
|
||||
- Stitch (flash chip info)
|
||||
- Super Maker (flash chip info, testing)
|
||||
- Tauwasser (research)
|
||||
- t5b6_de (flash chip info)
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -4,7 +4,7 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read(
|
|||
|
||||
setuptools.setup(
|
||||
name="FlashGBX",
|
||||
version="3.20",
|
||||
version="3.21",
|
||||
author="Lesserkuma",
|
||||
description="Reads and writes Game Boy and Game Boy Advance cartridge data. Supported hardware: GBxCart RW v1.3 and v1.4 by insideGadgets.",
|
||||
url="https://github.com/lesserkuma/FlashGBX",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user