This commit is contained in:
Lesserkuma 2021-06-03 13:09:55 +02:00
parent 6e45e3ce9a
commit 98399f00dc
27 changed files with 20724 additions and 19934 deletions

View File

@ -1,4 +1,20 @@
# Release notes
### v2.2 (released 2021-06-03)
- Added support for insideGadgets 2 MB, 32 KB FRAM, v1.0 *(thanks t5b6_de)*
- Added support for SD007_TSOP_29LV017D with M29W320DT *(thanks marv17)*
- Added support for SD007_TSOP_29LV017D with S29GL032M90T *(thanks marv17)*
- Fixed detection of Classic NES Series and Famicom Mini game cartridges for Game Boy Advance *(thanks LucentW)*
- Added support for 29LV128DBT2C-90Q and ALTERA CPLD *(thanks Sgt.DoudouMiel)*
- Added support for 0121 with 0121M0Y0BE *(thanks RetroGorek)*
- Fixed detection of Pocket Monsters Ruby v1.1 (AGB-AXVJ-JPN) and Pocket Monsters Sapphire v1.1 (AGB-AXPJ-JPN) genuine game cartridges *(thanks Icesythe7)*
- Fixed flash chip query for flash cartridges that have no CFI data but swapped pins *(thanks marv17)*
- Added support for M5M29G130AN (no PCB text) *(thanks Mr_V)*
- Added support for GA-07 with unlabeled flash chip *(thanks Mr_V)*
- 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 a DIY cart with MBC3 and MX29LV640 *(thanks eveningmoose)*
### v2.1 (released 2021-05-05)
- Fixed support for SD007_TSOP_29LV017D with L017D70VC *(thanks marv17 and 90sFlav)*
- Added support for a DIY cart with MBC1 and AM29F080 *(thanks skite2001)*

View File

@ -543,6 +543,10 @@ class FlashGBX_CLI():
if self.CONN.GetMode() == "DMG": cart_types = self.CONN.GetSupportedCartridgesDMG()
elif self.CONN.GetMode() == "AGB": cart_types = self.CONN.GetSupportedCartridgesAGB()
size = cart_types[1][detected[0]]["flash_size"]
if "manual_select" in cart_types[1][detected[0]]:
manual_select = cart_types[1][detected[0]]["manual_select"]
else:
manual_select = False
if "sector_size" in cart_types[1][detected[0]]:
sectors = cart_types[1][detected[0]]["sector_size"]
else:
@ -555,25 +559,29 @@ class FlashGBX_CLI():
sectors_undetected = True
cart_text += "- " + cart_types[0][detected[i]] + "\n"
if size_undetected:
(_, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type])
if isinstance(cfi, dict) and 'device_size' in cfi:
for i in range(0, len(detected)):
if cfi['device_size'] == cart_types[1][detected[i]]["flash_size"]:
cart_type = detected[i]
size_undetected = False
break
if len(detected) == 1:
msg_text = "The following flash cartridge type was detected:\n" + cart_text + "\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
if manual_select:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nHowever, there are differences between these cartridge types that cannot be detected automatically, so please select the correct cartridge type manually."
cart_type = 0
else:
if size_undetected is True:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nHowever, you may need to manually adjust the ROM size selection.\n\nIMPORTANT: While these cartridges share the same electronic signature, their supported ROM size can differ. As the size can not be detected automatically at this time, please select it manually."
if size_undetected:
(_, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type])
if isinstance(cfi, dict) and 'device_size' in cfi:
for i in range(0, len(detected)):
if cfi['device_size'] == cart_types[1][detected[i]]["flash_size"]:
cart_type = detected[i]
size_undetected = False
break
if len(detected) == 1:
msg_text = "The following flash cartridge type was detected:\n" + cart_text + "\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
else:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
if sectors_undetected and "sector_size_from_cfi" not in cart_types[1][cart_type]:
msg_text = msg_text + "\n\n{:s}IMPORTANT:{:s} While these share most of their attributes, some of them can not be automatically detected. If you encounter any errors while writing a ROM, please manually select the correct type based on the flash chip markings of your cartridge. Unchecking the “Prefer sector erase mode” config option can also help.".format(ANSI.RED, ANSI.RESET)
if size_undetected is True:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nHowever, you may need to manually adjust the ROM size selection.\n\nIMPORTANT: While these cartridges share the same electronic signature, their supported ROM size can differ. As the size can not be detected automatically at this time, please select it manually."
else:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
if sectors_undetected and "sector_size_from_cfi" not in cart_types[1][cart_type]:
msg_text = msg_text + "\n\n{:s}IMPORTANT:{:s} While these share most of their attributes, some of them can not be automatically detected. If you encounter any errors while writing a ROM, please manually select the correct type based on the flash chip markings of your cartridge. Unchecking the “Prefer sector erase mode” config option can also help.".format(ANSI.RED, ANSI.RESET)
print(msg_text)
if knownCartCFI:
@ -720,7 +728,7 @@ class FlashGBX_CLI():
if cart_type == 0:
msg_5v = ""
if mode == "DMG": msg_5v = "If your flash cartridge requires 5V to work, you can use the “--force-5v” command line switch, however please note that 5V can be unsafe for some flash chips."
print("\n{:s}Auto-detection failed. Please use the “--flashcart-handler” command line switch to select the flash cartridge handler manually.\n{:s}{:s}{:s}".format(ANSI.RED, ANSI.YELLOW, msg_5v, ANSI.RESET))
print("\n{:s}Auto-detection failed. Please use the “--flashcart-handler” command line switch to select the flash cartridge type manually.\n{:s}{:s}{:s}".format(ANSI.RED, ANSI.YELLOW, msg_5v, ANSI.RESET))
return
elif cart_type < 0: return
elif cart_type == 0 and args.flashcart_handler != "autodetect":
@ -734,8 +742,11 @@ class FlashGBX_CLI():
path = args.path
try:
if os.path.getsize(path) > 0x2000000: # reject too large files to avoid exploding RAM
print("{:s}Files bigger than 32 MB are not supported at this time.{:s}".format(ANSI.RED, ANSI.RESET))
if os.path.getsize(path) > 0x10000000: # reject too large files to avoid exploding RAM
print("{:s}ROM files bigger than 256 MB are not supported.{:s}".format(ANSI.RED, ANSI.RESET))
return
elif os.path.getsize(path) < 0x400:
print("{:s}ROM files smaller than 1 KB are not supported.{:s}".format(ANSI.RED, ANSI.RESET))
return
with open(path, "rb") as file: buffer = file.read()
except (PermissionError, FileNotFoundError):

View File

@ -933,7 +933,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
if answer == QtWidgets.QMessageBox.Yes:
(flash_id, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage)
if cfi_s == "":
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "Flash chip query result: <pre>" + flash_id + "</pre>There was no Common Flash Interface (CFI) response from the cartridge. Please clean the cartridge contacts and make sure that the cartridge is seated correctly. If a flash chip exists on the cartridge PCB, it may be too old or require unique unlocking and handling.", QtWidgets.QMessageBox.Ok)
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "Flash chip query result: <pre>" + flash_id + "</pre>There was no Common Flash Interface (CFI) response from the cartridge. It may be too old, not reflashable or the cartridge may not be seated correctly.", QtWidgets.QMessageBox.Ok)
else:
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "Flash chip query result: <pre>" + flash_id + "</pre><pre>" + str(cfi_s) + "</pre>", QtWidgets.QMessageBox.Ok)
with open(self.CONFIG_PATH + "/cfi.bin", "wb") as f: f.write(cfi['raw'])
@ -945,6 +945,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
if self.CONN.GetMode() == "DMG": cart_types = self.CONN.GetSupportedCartridgesDMG()
elif self.CONN.GetMode() == "AGB": cart_types = self.CONN.GetSupportedCartridgesAGB()
size = cart_types[1][detected[0]]["flash_size"]
if "manual_select" in cart_types[1][detected[0]]:
manual_select = cart_types[1][detected[0]]["manual_select"]
else:
manual_select = False
if "sector_size" in cart_types[1][detected[0]]:
sectors = cart_types[1][detected[0]]["sector_size"]
else:
@ -957,35 +961,43 @@ class FlashGBX_GUI(QtWidgets.QWidget):
sectors_undetected = True
cart_text += "- " + cart_types[0][detected[i]] + "\n"
if size_undetected:
(_, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type])
if isinstance(cfi, dict) and 'device_size' in cfi:
for i in range(0, len(detected)):
if cfi['device_size'] == cart_types[1][detected[i]]["flash_size"]:
cart_type = detected[i]
size_undetected = False
break
if len(detected) == 1:
msg_text = "The following flash cartridge type was detected:\n" + cart_text + "\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
if manual_select:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nHowever, there are differences between these cartridge types that cannot be detected automatically, so please select the correct cartridge type manually."
cart_type = 0
else:
if size_undetected is True:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nA compatible entry from this list will now be auto-selected, but you may need to manually adjust the ROM size selection.\n\nIMPORTANT: While these cartridges share the same electronic signature, their supported ROM size can differ. As the size can not be detected automatically at this time, please select it manually."
if size_undetected:
(_, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type])
if isinstance(cfi, dict) and 'device_size' in cfi:
for i in range(0, len(detected)):
if cfi['device_size'] == cart_types[1][detected[i]]["flash_size"]:
cart_type = detected[i]
size_undetected = False
break
if len(detected) == 1:
msg_text = "The following flash cartridge type was detected:\n" + cart_text + "\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
else:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nA compatible entry from this list will now be auto-selected.\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
if size_undetected is True:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nA compatible entry from this list will now be auto-selected, but you may need to manually adjust the ROM size selection.\n\nIMPORTANT: While these cartridges share the same electronic signature, their supported ROM size can differ. As the size can not be detected automatically at this time, please select it manually."
else:
msg_text = "Your cartridge responds to flash commands used by:\n" + cart_text + "\nA compatible entry from this list will now be auto-selected.\nThe supported ROM size is up to {:d} MB.".format(int(cart_types[1][cart_type]['flash_size'] / 1024 / 1024))
if sectors_undetected and "sector_size_from_cfi" not in cart_types[1][cart_type]:
msg_text = msg_text + "\n\n{:s}IMPORTANT:{:s} While these share most of their attributes, some of them can not be automatically detected. If you encounter any errors while writing a ROM, please manually select the correct type based on the flash chip markings of your cartridge. Enabling the “Prefer chip erase mode” config option can also help.".format(ANSI.RED, ANSI.RESET)
if sectors_undetected and "sector_size_from_cfi" not in cart_types[1][cart_type]:
msg_text = msg_text + "\n\n{:s}IMPORTANT:{:s} While these share most of their attributes, some of them can not be automatically detected. If you encounter any errors while writing a ROM, please manually select the correct type based on the flash chip markings of your cartridge. Enabling the “Prefer chip erase mode” config option can also help.".format(ANSI.RED, ANSI.RESET)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg_text)
button_ok = msgbox.addButton("&OK", QtWidgets.QMessageBox.ActionRole)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Information, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg_text)
if cart_type != 0:
button_ok = msgbox.addButton("&OK", QtWidgets.QMessageBox.ActionRole)
button_cancel = msgbox.addButton("&Cancel", QtWidgets.QMessageBox.RejectRole)
button_cfi = msgbox.addButton(" Run flash chip &query ", QtWidgets.QMessageBox.ActionRole)
msgbox.setDefaultButton(button_ok)
if cart_type != 0:
msgbox.setDefaultButton(button_ok)
else:
msgbox.setDefaultButton(button_cancel)
msgbox.setEscapeButton(button_cancel)
answer = msgbox.exec()
if msgbox.clickedButton() == button_cfi:
(flash_id, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type])
(flash_id, cfi_s, cfi) = self.CONN.CheckFlashChip(limitVoltage=limitVoltage, cart_type=cart_types[1][cart_type] if cart_type != 0 else None)
if cfi_s == "" or cfi == False:
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), "Flash chip query result: <pre>" + flash_id + "</pre>There was no Common Flash Interface (CFI) response from the cartridge. If a flash chip exists on the cartridge PCB, it may be too old or require unique unlocking and handling.", QtWidgets.QMessageBox.Ok)
else:
@ -1146,7 +1158,10 @@ class FlashGBX_GUI(QtWidgets.QWidget):
self.SETTINGS.setValue(setting_name, os.path.dirname(path))
if os.path.getsize(path) > 0x10000000: # reject too large files to avoid exploding RAM
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "Files bigger than 256 MB are not supported.", QtWidgets.QMessageBox.Ok)
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "ROM files bigger than 256 MB are not supported.", QtWidgets.QMessageBox.Ok)
return
elif os.path.getsize(path) < 0x400:
QtWidgets.QMessageBox.critical(self, "{:s} {:s}".format(APPNAME, VERSION), "ROM files smaller than 1 KB are not supported.", QtWidgets.QMessageBox.Ok)
return
with open(path, "rb") as file: buffer = bytearray(file.read(0x1000))
@ -1274,7 +1289,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
if self.CONN.GetMode() == "DMG" and features == 0x10 and not self.CONN.IsClkConnected():
rtc = False
else:
msg = "A Real Time Clock was detected on the cartridge. Do you want the cartridges Real Time Clock register values also to be saved?"
msg = "A Real Time Clock cartridge was detected. Do you want the cartridges Real Time Clock register values also to be saved?"
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel)
msgbox.setDefaultButton(QtWidgets.QMessageBox.Yes)
answer = msgbox.exec()
@ -1349,7 +1364,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
rtc = False
elif (self.CONN.GetMode() == "DMG" and ((features == 0xFE and (filesize == save_type + 0xC or erase)) or (self.CONN.IsClkConnected() and features == 0x10 and filesize == save_type + 0x30 or erase))) or \
(self.CONN.GetMode() == "AGB" and (filesize == Util.AGB_Header_Save_Sizes[save_type] + 0x10 or erase)):
msg = "A Real Time Clock was detected on the cartridge. Do you want the Real Time Clock register values to be also written?"
msg = "A Real Time Clock cartridge was detected. Do you want the Real Time Clock register values to be also written?"
cb = QtWidgets.QCheckBox("Update RTC", checked=True)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Question, windowTitle="{:s} {:s}".format(APPNAME, VERSION), text=msg, standardButtons=QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No | QtWidgets.QMessageBox.Cancel)
msgbox.setDefaultButton(QtWidgets.QMessageBox.Yes)

View File

@ -161,7 +161,7 @@ class Flashcart:
dprint("Flash ID: {:s}".format(' '.join(format(x, '02X') for x in cart_flash_id)))
verified = True
if cart_flash_id not in self.CONFIG["flash_ids"]:
dprint("WARNING: This Flash ID does not exist in flashcart handler file.")
dprint("This Flash ID does not exist in flashcart handler file.")
verified = False
return (verified, cart_flash_id)
@ -238,6 +238,7 @@ class Flashcart:
#sr_addr = self.CONFIG["commands"]["read_status_register"][j][0]
sr_data = self.CONFIG["commands"]["read_status_register"][j][1]
self.CartWrite([[addr, sr_data]])
self.CartRead(addr, 2) # dummy read (fixes some bootlegs)
wait_for = struct.unpack("<H", self.CartRead(addr, 2))[0]
dprint("Status Register Check: 0x{:X} & 0x{:X} == 0x{:X}? {:s}".format(wait_for, self.CONFIG["commands"]["chip_erase_wait_for"][i][2], data, str(wait_for == data)))
wait_for = wait_for & self.CONFIG["commands"]["chip_erase_wait_for"][i][2]
@ -281,6 +282,7 @@ class Flashcart:
sr_addr = self.CONFIG["commands"]["read_status_register"][j][0]
sr_data = self.CONFIG["commands"]["read_status_register"][j][1]
self.CartWrite([[sr_addr, sr_data]])
self.CartRead(addr, 2) # dummy read (fixes some bootlegs)
wait_for = struct.unpack("<H", self.CartRead(addr, 2))[0]
dprint("Status Register Check: 0x{:X} & 0x{:X} == 0x{:X}? {:s}".format(wait_for, self.CONFIG["commands"]["sector_erase_wait_for"][i][2], data, str(wait_for & self.CONFIG["commands"]["sector_erase_wait_for"][i][2] == data)))
wait_for = wait_for & self.CONFIG["commands"]["sector_erase_wait_for"][i][2]
@ -320,6 +322,7 @@ class Flashcart:
class CFI:
def Parse(self, buffer):
if buffer is False or buffer == b'': return False
buffer = copy.copy(buffer)
info = {}
magic = "{:s}{:s}{:s}".format(chr(buffer[0x20]), chr(buffer[0x22]), chr(buffer[0x24]))

View File

@ -7,12 +7,12 @@ from enum import Enum
# Common constants
APPNAME = "FlashGBX"
VERSION_PEP440 = "2.1"
VERSION_PEP440 = "2.2"
VERSION = "v{:s}".format(VERSION_PEP440)
DEBUG = False
AGB_Header_ROM_Sizes = [ "4 MB", "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB" ]
AGB_Header_ROM_Sizes_Map = [ 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000 ]
AGB_Header_ROM_Sizes = [ "1 MB", "2 MB", "4 MB", "8 MB", "16 MB", "32 MB", "64 MB", "128 MB", "256 MB" ]
AGB_Header_ROM_Sizes_Map = [ 0x100000, 0x200000, 0x400000, 0x800000, 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000 ]
AGB_Header_Save_Types = [ "None", "4K EEPROM (512 Bytes)", "64K EEPROM (8 KB)", "256K SRAM (32 KB)", "512K SRAM (64 KB)", "1M SRAM (128 KB)", "512K FLASH (64 KB)", "1M FLASH (128 KB)", "8M DACS (1008 KB)" ]
AGB_Header_Save_Sizes = [ 0, 512, 8192, 32768, 65536, 131072, 65536, 131072, 1032192 ]
AGB_Global_CRC32 = 0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
{
"type":"AGB",
"names":[
"B11 with 26L6420MC-90"
],
"flash_ids":[
[ 0xC2, 0x00, 0xFC, 0x22 ]
],
"voltage":3.3,
"flash_size":0x800000,
"chip_erase_timeout":200,
"command_set":"AMD",
"commands":{
"reset":[
[ 0, 0xF0 ]
],
"read_identifier":[
[ 0xAAA, 0xAA ],
[ 0x555, 0x55 ],
[ 0xAAA, 0x90 ]
],
"read_cfi":[
[ 0xAA, 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, 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 ]
]
}
}

View File

@ -0,0 +1,71 @@
{
"type":"AGB",
"names":[
"29LV128DBT2C-90Q and ALTERA CPLD"
],
"flash_ids":[
[ 0xC2, 0x00, 0x7A, 0x22 ]
],
"voltage":3.3,
"flash_size":0x1000000,
"sector_size_from_cfi":true,
"chip_erase_timeout":120,
"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 ]
],
"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 ]
]
}
}

View File

@ -1,16 +1,16 @@
{
"type":"AGB",
"names":[
"4050M0Y0Q0-39VF512 with 4050M0Y0Q0"
"4050M0Y0Q0-39VF512 with 4050M0Y0Q0",
"0121 with 0121M0Y0BE"
],
"flash_ids":[
[ 0x8A, 0x00, 0x02, 0x89 ]
[ 0x8A, 0x00, 0x02, 0x89 ],
[ 0x8A, 0x00, 0x7D, 0x88 ]
],
"voltage":3.3,
"flash_size":0x2000000,
"sector_size":0x40000,
"reset_every":0x400000,
"buffer_size":1024,
"command_set":"INTEL",
"commands":{
"reset":[

View File

@ -0,0 +1,47 @@
{
"type":"AGB",
"names":[
"GA-07 with unlabeled flash chip"
],
"flash_ids":[
[ 0x1C, 0x00, 0x2B, 0x00 ]
],
"voltage":3.3,
"flash_size":0x800000,
"sector_size":[
[0x2000, 8],
[0x10000, 127]
],
"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 ]
]
}
}

View File

@ -0,0 +1,40 @@
{
"type":"AGB",
"names":[
"Generic Flash Cartridge (0/90)"
],
"voltage":3.3,
"chip_erase_timeout":120,
"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, 0x10 ],
[ "PA", "PD" ]
],
"single_write_wait_for":[
[ 0, 0x80, 0x80 ],
[ null, null, null ],
[ null, null, null ]
]
}
}

View File

@ -0,0 +1,47 @@
{
"type":"AGB",
"names":[
"M5M29G130AN (no PCB text)"
],
"flash_ids":[
[ 0x1C, 0x00, 0x3D, 0x00 ]
],
"voltage":3.3,
"flash_size":0x1000000,
"sector_size":[
[0x10000, 255],
[0x2000, 8]
],
"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 ]
]
}
}

View File

@ -35,7 +35,7 @@
],
"single_write":[
[ 0, 0x70 ],
[ 0, 0x10 ],
[ 0, 0x40 ],
[ "PA", "PD" ]
],
"single_write_wait_for":[

View File

@ -0,0 +1,58 @@
{
"type":"DMG",
"names":[
"DIY cart with MBC3 and MX29LV640 @ AUDIO"
],
"flash_ids":[
[ 0xC2, 0xC2, 0xCB, 0xCB ]
],
"voltage":3.3,
"flash_size":0x800000,
"start_addr":0,
"first_bank":1,
"mbc":3,
"write_pin":"AUDIO",
"chip_erase_timeout":200,
"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 ]
],
"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 ]
]
}
}

View File

@ -13,7 +13,6 @@
[ 0xBF, 0x00, 0x54, 0x73 ]
],
"voltage":3.3,
"voltage_variants":true,
"flash_size":0x400000,
"start_addr":0,
"first_bank":1,

View File

@ -1,9 +1,11 @@
{
"type":"DMG",
"names":[
"DIY cart with AM29F016/AM29F016B @ WR"
"DIY cart with AM29F016/AM29F016B @ WR",
"insideGadgets 2 MB, 32 KB FRAM, v1.0"
],
"flash_ids":[
[ 0x01, 0xAD, 0x00, 0x00 ],
[ 0x01, 0xAD, 0x00, 0x00 ]
],
"voltage":5,

View File

@ -12,7 +12,7 @@
[ 0x02, 0x02, 0x4A, 0x4A ],
[ 0x02, 0xC8, 0x00, 0x00 ]
],
"voltage":5,
"voltage":3.3,
"flash_size":0x200000,
"start_addr":0,
"first_bank":1,

View File

@ -10,6 +10,7 @@
[ 0x02, 0x02, 0x7D, 0x7D ],
[ 0x02, 0x02, 0x7D, 0x7D ]
],
"manual_select":true,
"voltage":3.3,
"flash_size":0x400000,
"start_addr":0x4000,
@ -20,6 +21,7 @@
[0x10000, 63]
],
"chip_erase_timeout":60,
"mbc":5,
"command_set":"AMD",
"commands":{
"reset":[

View File

@ -0,0 +1,75 @@
{
"type":"DMG",
"names":[
"SD007_TSOP_29LV017D with M29W320DT",
"SD007_TSOP_48BALL_V10 with M29W320DT"
],
"flash_ids":[
[ 0x02, 0x02, 0x7D, 0x7D ],
[ 0x20, 0x20, 0xC9, 0xC9 ]
],
"voltage":3.3,
"flash_size":0x400000,
"start_addr":0x4000,
"first_bank":0,
"write_pin":"WR",
"chip_erase_timeout":60,
"command_set":"AMD",
"commands":{
"reset":[
[ 0, 0xF0 ]
],
"read_identifier":[
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ 0xAAA, 0x90 ]
],
"read_cfi":[
[ 0xAA, 0x98 ]
],
"chip_erase":[
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ 0xAAA, 0x80 ],
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ 0xAAA, 0x10 ]
],
"chip_erase_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ 0, 0xFF, 0xFF ]
],
"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 ]
]
}
}

View File

@ -0,0 +1,91 @@
{
"type":"DMG",
"names":[
"SD007_TSOP_29LV017D with S29GL032M90T"
],
"flash_ids":[
[ 0x02, 0x02, 0x7D, 0x7D ]
],
"manual_select":true,
"voltage":3.3,
"flash_size":0x400000,
"start_addr":0,
"first_bank":1,
"write_pin":"WR",
"sector_size_from_cfi":true,
"chip_erase_timeout":120,
"command_set":"AMD",
"commands":{
"reset":[
[ 0, 0xF0 ]
],
"read_identifier":[
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ 0xAAA, 0x90 ]
],
"read_cfi":[
[ 0xAAA, 0x98 ]
],
"chip_erase":[
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ 0xAAA, 0x80 ],
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ 0xAAA, 0x10 ]
],
"chip_erase_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ 0, 0xFF, 0xFF ]
],
"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 ]
],
"buffer_write":[
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ "SA", 0x26 ],
[ "SA", "BS" ],
[ "PA", "PD" ],
[ "SA", 0x2A ]
],
"buffer_write_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],
[ "SA", "PD", 0xFFFF ]
],
"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 ]
]
}
}

View File

@ -1,12 +1,10 @@
{
"type":"DMG",
"names":[
"insideGadgets 2 MB, 128 KB SRAM/32 KB FRAM",
"insideGadgets 2 MB, 128 KB SRAM/32 KB FRAM"
],
"flash_ids":[
[ 0x01, 0x01, 0xD2, 0xD2 ],
[ 0x01, 0xAD, 0x00, 0x00 ]
[ 0x01, 0x01, 0xD2, 0xD2 ]
],
"voltage":5,
"flash_size":0x200000,

View File

@ -297,8 +297,10 @@ class FirmwareUpdater(QtWidgets.QDialog):
fncSetStatus(text="Status: Waiting for bootloader...", setProgress=0)
if self.ResetAVR(delay) is False:
fncSetStatus(text="Status: Device reboot error.", enableUI=True)
fncSetStatus(text="Status: Bootloader error.", enableUI=True)
self.prgStatus.setValue(0)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful as the GBxCart RW v1.3 bootloader is not responding. If it doesnt work even after multiple retries, please use the official firmware updater instead.", standardButtons=QtWidgets.QMessageBox.Ok)
answer = msgbox.exec()
return 2
while True:
@ -322,13 +324,17 @@ class FirmwareUpdater(QtWidgets.QDialog):
time.sleep(1)
if len(buffer) != 0x11:
delay += 0.05
fncSetStatus("Status: Waiting for bootloader... (+{:d}ms)".format(int(delay * 1000)))
fncSetStatus("Status: Waiting for bootloader... (+{:d}ms)".format(math.ceil(delay * 1000)))
if self.ResetAVR(delay) is False:
fncSetStatus(text="Status: Device reboot error.", enableUI=True)
fncSetStatus(text="Status: Bootloader error.", enableUI=True)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful as the GBxCart RW v1.3 bootloader is not responding. If it doesnt work even after multiple retries, please use the official firmware updater instead.", standardButtons=QtWidgets.QMessageBox.Ok)
answer = msgbox.exec()
return 2
lives -= 1
if lives < 0:
fncSetStatus(text="Status: Device reboot error.", enableUI=True)
fncSetStatus(text="Status: Bootloader timeout.", enableUI=True)
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text="The firmware update was not successful as the GBxCart RW v1.3 bootloader is not responding. If it doesnt work even after multiple retries, please use the official firmware updater instead.", standardButtons=QtWidgets.QMessageBox.Ok)
answer = msgbox.exec()
return 2
continue
break

View File

@ -411,7 +411,7 @@ class GbxDevice:
return self.ReadROM(address, length)
def _cart_write(self, address, value, flashcart=False, sram=False):
#dprint("Writing to cartridge: 0x{:X} = 0x{:X}".format(address, value & 0xFF))
dprint("Writing to cartridge: 0x{:X} = 0x{:X}".format(address, value & 0xFF))
if self.MODE == "DMG":
if flashcart:
buffer = bytearray([self.DEVICE_CMD["DMG_FLASH_WRITE_BYTE"]])
@ -523,7 +523,9 @@ class GbxDevice:
header = self.ReadROM(0, 0x180)
if len(header) != 0x180: raise Exception("Couldnt read the cartridge information. Please try again.")
if Util.DEBUG:
with open("debug_header.bin", "wb") as f: f.write(header)
# Check for DACS
dacs_8m = False
if header[0x04:0x04+0x9C] == bytearray([0x00] * 0x9C):
@ -536,11 +538,23 @@ class GbxDevice:
# Parse ROM header
if self.MODE == "DMG":
data = RomFileDMG(header).GetHeader()
if data["logo_correct"] is False: # try to fix weird bootlegs
self._cart_write(0, 0xFF)
time.sleep(0.1)
header = self.ReadROM(0, 0x180)
data = RomFileDMG(header).GetHeader()
_mbc = DMG_MBC().GetInstance(args={"mbc":data["features_raw"]}, cart_write_fncptr=self._cart_write, cart_read_fncptr=self._cart_read, clk_toggle_fncptr=self._clk_toggle)
self.INFO["has_rtc"] = _mbc.HasRTC() is True
elif self.MODE == "AGB":
data = RomFileAGB(header).GetHeader()
if data["logo_correct"] is False: # try to fix weird bootlegs
self._cart_write(0, 0xFF)
time.sleep(0.1)
header = self.ReadROM(0, 0x180)
data = RomFileAGB(header).GetHeader()
size_check = header[0xA0:0xA0+16]
currAddr = 0x400000
while currAddr < 0x2000000:
@ -553,7 +567,7 @@ class GbxDevice:
elif dacs_8m:
data["dacs_8m"] = True
if header[0xC5] == 0 and header[0xC7] == 0 and header[0xC9] == 0:
if 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, clk_toggle_fncptr=self._clk_toggle)
has_rtc = _agb_gpio.HasRTC()
data["has_rtc"] = has_rtc is True
@ -569,7 +583,6 @@ class GbxDevice:
self.INFO["last_action"] = 0
if self.MODE == "DMG" and setPinsAsInputs: self._write(self.DEVICE_CMD["SET_ADDR_AS_INPUTS"])
#with open("debug.bin", "wb") as f: f.write(header)
return data
def ReadROM(self, address, length, skip_init=False, max_length=64):
@ -1121,6 +1134,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, 64)[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:
@ -1133,7 +1147,30 @@ class GbxDevice:
self._cart_write(method['reset'][i][0], method['reset'][i][1], flashcart=True)
cfi["method"] = method
else:
for j in range(0, 2):
if j == 1:
d_swap = ( 0, 1 )
for k in method.keys():
for c in range(0, len(method[k])):
if isinstance(method[k][c][1], int):
method[k][c][1] = bitswap(method[k][c][1], d_swap)
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, 64)[0:8]
if flash_id == check_buffer[:len(flash_id)]: continue
if self.MODE == "DMG":
method_string = "[" + we.ljust(5) + "/{:4X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
else:
method_string = "[{:6X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
line_exists = False
for i in range(0, len(flash_id_lines)):
if method_string == flash_id_lines[i][0]: line_exists = True
if not line_exists: flash_id_lines.append([method_string, flash_id])
for i in range(0, len(method['reset'])):
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_meta = copy.deepcopy(cart_type)
if "reset" in flashcart_meta["commands"]:
@ -1799,6 +1836,12 @@ class GbxDevice:
cart_type = copy.deepcopy(supported_carts[args["cart_type"]])
if cart_type == "RETAIL" or cart_type == "AUTODETECT": return False # Generic ROM Cartridge is not flashable
# Firmware check L1
if "flash_commands_on_bank_1" in cart_type:
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is currently not supported by FlashGBX. Please try the official GBxCart RW firmware and interface software instead.", "abortable":False})
return False
# Firmware check L1
cart_type["_index"] = 0
for i in range(0, len(list(self.SUPPORTED_CARTS[self.MODE].keys()))):
if i == args["cart_type"]:

View File

@ -112,6 +112,9 @@ class GbxDevice:
"USART_1_7M_SPEED":'>',
"CLK_HIGH":'K',
"CLK_LOW":'[',
"CART_PWR_ON":'/',
"CART_PWR_OFF":'.',
"QUERY_CART_PWR":']'
}
PCB_VERSIONS = {1:'v1.0', 2:'v1.1', 4:'v1.3', 90:'XMAS', 100:'Mini'}
SUPPORTED_CARTS = {}
@ -200,10 +203,13 @@ class GbxDevice:
pass
if self.FW[1] not in self.PCB_VERSIONS.keys():
dev.close()
self.DEVICE = None
continue
#pass
if Util.DEBUG is True and self.FW[1] == 5:
self.PCB_VERSIONS[5] = "v1.4"
pass
else:
dev.close()
self.DEVICE = None
continue
if (self.FW[1] != 4):
conn_msg.append([0, "NOTE: This version of FlashGBX was developed to be used with GBxCart RW v1.3 and v1.3 Pro. Other revisions are untested and may not be fully compatible."])
@ -736,6 +742,16 @@ class GbxDevice:
else:
return buffer[0]
def CartPowerOn(self):
if self.FW[1] == 5:
self.write(self.DEVICE_CMD["QUERY_CART_PWR"])
ret = self.DEVICE.read(1)
if ret == b'\x00':
self.set_mode(self.DEVICE_CMD["CART_PWR_ON"])
print("POWER ON")
time.sleep(0.2)
self.DEVICE.reset_input_buffer() # bug workaround
def SetMode(self, mode):
if mode == "DMG":
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
@ -744,6 +760,7 @@ class GbxDevice:
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
self.MODE = "AGB"
self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
self.CartPowerOn()
def AutoDetectFlash(self, limitVoltage=False):
flash_types = []
@ -1060,6 +1077,8 @@ class GbxDevice:
header = self.ReadROM(0, 0x180)
if len(header) != 0x180: raise Exception("Couldnt read the cartridge information. Please try again.")
if Util.DEBUG:
with open("debug_header.bin", "wb") as f: f.write(header)
# Check for DACS
dacs_8m = False
@ -1835,6 +1854,10 @@ class GbxDevice:
# Firmware check
#dprint(flashcart_meta)
if "flash_commands_on_bank_1" in cart_type:
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is currently not supported by FlashGBX. Please try the official GBxCart RW firmware and interface software instead.", "abortable":False})
return False
# Set Voltage
if voltage == 3.3:
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])

Binary file not shown.

View File

@ -56,11 +56,13 @@ for Windows, Linux, macOS
- DIY cart with AM29F032/AM29F032B
- DIY cart with AT49F040
- DIY cart with MBC1 and AM29F080
- DIY cart with MBC3 and MX29LV640
- GB Smart 32M
- insideGadgets 32 KB
- insideGadgets 512 KB
- insideGadgets 1 MB, 128 KB SRAM
- insideGadgets 2 MB, 128 KB SRAM/32 KB FRAM
- insideGadgets 2 MB, 32 KB FRAM, v1.0
- insideGadgets 4 MB, 128 KB SRAM/FRAM
- insideGadgets 4 MB, 32 KB FRAM, MBC3+RTC
- Mr Flash 64M
@ -86,7 +88,7 @@ for Windows, Linux, macOS
- GB-M968 with 29LV160DB
- GB-M968 with M29W160EB
- GB-M968 with MX29LV320ABTC
- S29GL032N90T and ALTERA CPLD (configured for MBC5)
- S29GL032N90T and ALTERA CPLD configured for MBC5
- SD007_48BALL_64M with GL032M11BAIR4
- SD007_48BALL_64M with M29W640
- SD007_48BALL_64M_V2 with GL032M11BAIR4
@ -106,16 +108,20 @@ for Windows, Linux, macOS
- SD007_BV5_V3 with AM29LV160MB
- SD007_K8D3216_32M with MX29LV160CT
- SD007_TSOP_29LV017D with L017D70VC
- SD007_TSOP_29LV017D with S29GL032M90T
- SD007_TSOP_48BALL with 36VF3204
- SD007_TSOP_48BALL with AM29LV160DB
- SD007_TSOP_48BALL with K8D3216UTC
- SD007_TSOP_48BALL with M29W160ET
- SD007_TSOP_48BALL with L160DB12VI
- SD007_TSOP_48BALL_V10 with M29W320DT
- Game Boy Advance
- 0121 with 0121M0Y0BE
- 100BS6600_48BALL_V4 with 6600M0U0BE
- 28F256L03B-DRV with 256L30B
- 29LV128DBT2C-90Q and ALTERA CPLD
- 36L0R8-39VF512 with M36L0R8060B
- 36L0R8-39VF512 with M36L0R8060T
- 4350Q2 with 4350LLYBQ2
@ -139,7 +145,9 @@ for Windows, Linux, macOS
- BX2006_TSOP_64BALL with GL256S
- BX2006_TSOPBGA_0106 with M29W640GB6AZA6
- BX2006_TSOPBGA_0106 with K8D6316UTM-PI07
- GA-07 with unlabeled flash chip
- GE28F128W30 with 128W30B0
- M5M29G130AN (no PCB text)
- M6MGJ927 (no PCB text)
Many different reproduction cartridges share their flash chip command set, so even if yours is not on this list, it may still work fine or even be auto-detected as another one. Support for more cartridges can also be added by creating external config files that include the necessary flash chip commands.
@ -195,10 +203,12 @@ The author would like to thank the following very kind people for their help and
- bbsan (flash chip info)
- ClassicOldSong (bug reports)
- djedditt (testing)
- dyf2007 (flash chip info)
- easthighNerd (feature suggestions)
- eveningmoose (flash chip info)
- Frost Clock (flash chip info)
- howie0210 (flash chip info)
- Icesythe7 (feature suggestions)
- Icesythe7 (feature suggestions, testing, bug reports)
- Jayro (flash chip info)
- JFox (help with properly packaging the app for pip)
- julgr (macOS help, testing)
@ -206,11 +216,15 @@ The author would like to thank the following very kind people for their help and
- LovelyA72 (flash chip info)
- LucentW (flash chip info, testing, bug reports)
- marv17 (flash chip info, testing, bug reports, feature suggestions)
- Mr_V (flash chip info, testing)
- paarongiroux (bug reports)
- Paradoxical (flash chip info)
- RetroGorek (flash chip info)
- RevZ (Linux help, testing, bug reports, flash chip info)
- Sgt.DoudouMiel (flash chip info)
- skite2001 (flash chip info)
- Super Maker (flash chip info, testing)
- t5b6_de (flash chip info)
- Veund (flash chip info)
- Zeii (flash chip info)
- Zelante (flash chip info)

View File

@ -4,7 +4,7 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read(
setuptools.setup(
name="FlashGBX",
version="2.1",
version="2.2",
author="Lesserkuma",
description="Reads and writes Game Boy and Game Boy Advance cartridge data. Currently supports the GBxCart RW hardware device by insideGadgets.",
url="https://github.com/lesserkuma/FlashGBX",