This commit is contained in:
Lesserkuma
2023-05-14 13:15:39 +02:00
parent c94e76d8cb
commit 97d4a3a00b
10 changed files with 47 additions and 32 deletions

View File

@@ -1,4 +1,11 @@
# Release notes
### v3.29 (released 2023-05-14)
- Fixed an issue with writing to some flash cartridges using the old GBxCart RW v1.3 hardware revision *(thanks yosoo)*
- Fixed an issue with Batteryless SRAM save data restore *(thanks antPL)*
- Confirmed support for SD007_TSOP_64BALL_SOP28_V2 with unlabeled flash chip *(thanks DevDavisNunez)*
- Added support for SD007_BGA48_71TV_T28_DEEP with M29W640 *(thanks Cristóbal)*
- Minor bug fixes and improvements
### v3.28 (released 2023-05-05)
- Improved support for the BennVenn MBC3000 RTC cart; can now write to Real Time Clock registers
- Updated the Game Boy Advance lookup database for save types, ROM sizes and checksums

View File

@@ -202,7 +202,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
self.mnuConfig.addAction("Check for &updates on application startup", lambda: [ self.EnableUpdateCheck() ])
self.mnuConfig.addAction("&Append date && time to filename of save data backups", lambda: self.SETTINGS.setValue("SaveFileNameAddDateTime", str(self.mnuConfig.actions()[1].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
self.mnuConfig.addAction("Prefer full &chip erase", lambda: self.SETTINGS.setValue("PreferChipErase", str(self.mnuConfig.actions()[2].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
self.mnuConfig.addAction("Extra data &verification", lambda: self.SETTINGS.setValue("VerifyData", str(self.mnuConfig.actions()[3].isChecked()).lower().replace("true", "enabled").replace("false", "disabled")))
self.mnuConfig.addAction("&Verify written data", lambda: self.SETTINGS.setValue("VerifyData", 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("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")))
@@ -1613,7 +1613,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
if self.CONN.GetMode() == "DMG" and mbc in (0x10, 0x110) and not self.CONN.IsClkConnected():
rtc = False
elif erase or Util.save_size_includes_rtc(mode=self.CONN.GetMode(), mbc=mbc, save_size=filesize, save_type=save_type):
msg = "A Real Time Clock cartridge was detected. 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 written as well?"
cb = QtWidgets.QCheckBox("&Adjust 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

@@ -129,8 +129,8 @@ class Flashcart:
if "write_pin" not in self.CONFIG: return False
return (self.CONFIG["write_pin"] == "WR+RESET")
def GetFlashSize(self):
if "flash_size" not in self.CONFIG: return False
def GetFlashSize(self, default=False):
if "flash_size" not in self.CONFIG: return default
return self.CONFIG["flash_size"]
def GetBufferSize(self):

View File

@@ -7,9 +7,9 @@ from enum import Enum
# Common constants
APPNAME = "FlashGBX"
VERSION_PEP440 = "3.28"
VERSION_PEP440 = "3.29"
VERSION = "v{:s}".format(VERSION_PEP440)
VERSION_TIMESTAMP = 1683283512
VERSION_TIMESTAMP = 1684066518
DEBUG = False
DEBUG_LOG = []
APP_PATH = ""
@@ -841,13 +841,14 @@ def get_mbc_name(id):
def save_size_includes_rtc(mode, mbc, save_size, save_type):
rtc_size = 0x10
if mode == "DMG":
save_type = DMG_Header_RAM_Sizes_Map.index(save_type)
if get_mbc_name(mbc) in ("MBC3", "MBC30"): rtc_size = 0x30
elif get_mbc_name(mbc) == "HuC-3": rtc_size = 0x0C
elif get_mbc_name(mbc) == "TAMA5": rtc_size = 0x28
return (((DMG_Header_RAM_Sizes_Flasher_Map[save_type] + rtc_size) % save_size) != rtc_size)
return (((DMG_Header_RAM_Sizes_Flasher_Map[save_type] + rtc_size) % save_size) == 0)
elif mode == "AGB":
rtc_size = 0x10
return (((AGB_Header_Save_Sizes[save_type] + rtc_size) % save_size) != rtc_size)
return (((AGB_Header_Save_Sizes[save_type] + rtc_size) % save_size) == 0)
return False
def validate_datetime_format(string, format):

View File

@@ -4,13 +4,15 @@
"SD007_48BALL_64M with GL032M11BAIR4",
"SD007_48BALL_64M_V2 with GL032M11BAIR4",
"S29GL032N90T and ALTERA CPLD (MBC5)",
"29LV320TE and ALTERA CPLD (no PCB text)"
"29LV320TE and ALTERA CPLD (no PCB text)",
"SD007_TSOP_64BALL_SOP28_V2 with unlabeled flash chip"
],
"flash_ids":[
[ 0x02, 0x02, 0x7D, 0x7D ],
[ 0x02, 0x02, 0x7D, 0x7D ],
[ 0x02, 0x02, 0x7D, 0x7D ],
[ 0x04, 0x04, 0xF5, 0xF5 ]
[ 0x04, 0x04, 0xF5, 0xF5 ],
[ 0x02, 0x02, 0x7D, 0x7D ]
],
"voltage":3.3,
"flash_size":0x400000,

View File

@@ -1,9 +1,11 @@
{
"type":"DMG",
"names":[
"SD007_48BALL_64M with M29W640"
"SD007_48BALL_64M with M29W640",
"SD007_BGA48_71TV_T28_DEEP with M29W640"
],
"flash_ids":[
[ 0x20, 0x00, 0x7D, 0x00 ],
[ 0x20, 0x00, 0x7D, 0x00 ]
],
"voltage":3.3,
@@ -11,11 +13,8 @@
"start_addr":0,
"first_bank":1,
"write_pin":"WR",
"sector_size":[
[0x02000, 8],
[0x10000, 127]
],
"chip_erase_timeout":70,
"sector_size_from_cfi":true,
"_chip_erase_timeout":70,
"command_set":"AMD",
"commands":{
"reset":[
@@ -29,7 +28,7 @@
"read_cfi":[
[ 0xAA, 0x98 ]
],
"chip_erase":[
"_chip_erase":[
[ 0xAAA, 0xA9 ],
[ 0x555, 0x56 ],
[ 0xAAA, 0x80 ],
@@ -37,7 +36,7 @@
[ 0x555, 0x56 ],
[ 0xAAA, 0x10 ]
],
"chip_erase_wait_for":[
"_chip_erase_wait_for":[
[ null, null, null ],
[ null, null, null ],
[ null, null, null ],

View File

@@ -683,26 +683,26 @@ class GbxDevice:
if Util.DEBUG:
with open("debug_header.bin", "wb") as f: f.write(header)
if header is False or len(header) != 0x180:
print("{:s}\n{:s}Couldnt read the cartridge information. Please try again.{:s}".format(str(header), ANSI.RED, ANSI.RESET))
return False
# Parse ROM header
if self.MODE == "DMG":
data = RomFileDMG(header).GetHeader()
if data["game_title"] == "TETRIS" and hashlib.sha1(header).digest() != bytearray([0x1D, 0x69, 0x2A, 0x4B, 0x31, 0x7A, 0xA5, 0xE9, 0x67, 0xEE, 0xC2, 0x2F, 0xCC, 0x32, 0x43, 0x8C, 0xCB, 0xC5, 0x78, 0x0B]): # Sachen
if "game_title" in data and data["game_title"] == "TETRIS" and hashlib.sha1(header).digest() != bytearray([0x1D, 0x69, 0x2A, 0x4B, 0x31, 0x7A, 0xA5, 0xE9, 0x67, 0xEE, 0xC2, 0x2F, 0xCC, 0x32, 0x43, 0x8C, 0xCB, 0xC5, 0x78, 0x0B]): # Sachen
header = self.ReadROM(0, 0x280)
data = RomFileDMG(header).GetHeader()
if data["logo_correct"] is False and not b"Future Console Design" in header: # workaround for strange bootlegs
if "logo_correct" in data and data["logo_correct"] is False and not b"Future Console Design" in header: # workaround for strange bootlegs
self._cart_write(0, 0xFF)
time.sleep(0.1)
header = self.ReadROM(0, 0x280)
data = RomFileDMG(header).GetHeader()
if data["mapper_raw"] == 0x203 or b"Future Console Design" in header: # Xploder GB version number
if "mapper_raw" in data and data["mapper_raw"] == 0x203 or b"Future Console Design" in header: # Xploder GB version number
self._cart_write(0x0006, 0)
header[0:0x10] = self.ReadROM(0x4000, 0x10)
header[0xD0:0xE0] = self.ReadROM(0x40D0, 0x10)
data = RomFileDMG(header).GetHeader()
if data == {}: return False
data["has_rtc"] = False
data["rtc_string"] = "Not available"
if data["logo_correct"] is True:
@@ -1100,11 +1100,13 @@ class GbxDevice:
elif self.MODE == "AGB":
command = "AGB_CART_READ"
for _ in range(0, num):
for n in range(0, num):
self._write(self.DEVICE_CMD[command])
temp = self._read(length)
if isinstance(temp, int): temp = bytearray([temp])
if temp is False or len(temp) != length: return bytearray()
if temp is False or len(temp) != length:
print("{:s}Error while trying to read 0x{:X} bytes from cartridge ROM at 0x{:X} in iteration {:d} of {:d}:{:s}\n{:s}".format(ANSI.RED, length, address, n, num, ANSI.RESET, str(temp)))
return bytearray()
buffer += temp
if self.INFO["action"] in (self.ACTIONS["ROM_READ"], self.ACTIONS["SAVE_READ"], self.ACTIONS["ROM_WRITE_VERIFY"]) and not self.NO_PROG_UPDATE:
self.SetProgress({"action":"READ", "bytes_added":len(temp)})
@@ -1379,9 +1381,6 @@ class GbxDevice:
if ret != 0x03: self._write(self.DEVICE_CMD["FLASH_PROGRAM"])
ret = self._write(data, wait=True)
if rumble_stop and i == 0:
dprint("Sending rumble stop command")
self._cart_write(address=0xC6, value=0x00, flashcart=True)
if ret not in (0x01, 0x03):
dprint("Flash error at 0x{:X} in iteration {:d} of {:d} while trying to write a total of 0x{:X} bytes (response = {:s})".format(address, i, num, len(buffer), str(ret)))
@@ -1389,6 +1388,11 @@ class GbxDevice:
self.SKIPPING = False
return False
pos += len(data)
if rumble_stop and pos % flash_buffer_size == 0:
dprint("Sending rumble stop command")
self._cart_write(address=0xC6, value=0x00, flashcart=True)
rumble_stop = False
address += length
if ((pos % length) * 10 == 0) and (self.INFO["action"] in (self.ACTIONS["ROM_WRITE"], self.ACTIONS["SAVE_WRITE"]) and not self.NO_PROG_UPDATE):
@@ -3292,7 +3296,7 @@ class GbxDevice:
flash_capacity = len(data_import)
if sector_map is not None and sector_map is not False:
smallest_sector_size = flashcart.GetSmallestSectorSize()
sector_offsets = flashcart.GetSectorOffsets(rom_size=len(data_import), rom_bank_size=rom_bank_size)
sector_offsets = flashcart.GetSectorOffsets(rom_size=flashcart.GetFlashSize(default=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) and not (flashcart.SupportsChipErase() and args["prefer_chip_erase"]):
@@ -3365,7 +3369,7 @@ class GbxDevice:
# ↓↓↓ Chip erase
chip_erase = False
if flashcart.SupportsChipErase():
if flashcart.SupportsChipErase() and not flash_offset > 0:
if flashcart.SupportsSectorErase() and args["prefer_chip_erase"] is False and sector_map is not False:
chip_erase = False
else:

Binary file not shown.

View File

@@ -176,6 +176,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
- SD007_48BALL_64M_V6 with 29DL163BD-90
- SD007_48BALL_64M_V8 with M29W160ET
- SD007_48BALL_SOP28 with M29W320ET
- SD007_BGA48_71TV_T28_DEEP with M29W640
- SD007_BV5 with 29LV160TE-70PFTN
- SD007_BV5_DRV with M29W320DT
- SD007_BV5_DRV with S29GL032M90TFIR4
@@ -207,6 +208,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
- SD007_TSOP_64BALL_SOJ28 with unlabeled flash chip
- SD007_TSOP_64BALL_SOP28 with EN29LV160AB-70TCP
- SD007_TSOP_64BALL_SOP28 with unlabeled flash chip
- SD007_TSOP_64BALL_SOP28_V2 with unlabeled flash chip
- SD008-6810-512S with MSP55LV512
- SD008-6810-V4 with MX29GL256EL
- SD008-6810-V5 with MX29CL256FH
@@ -302,7 +304,7 @@ Many different reproduction cartridges share their flash chip command set, so ev
The author would like to thank the following very kind people for their help, contributions or documentation (in alphabetical order):
2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, bbsan, BennVenn, ccs21, ClassicOldSong, CodyWick13, Corborg, crizzlycruz, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, KOOORAY, kscheel, kyokohunter, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, Zeii, Zelante, zvxr
2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, bbsan, BennVenn, ccs21, ClassicOldSong, CodyWick13, Corborg, Cristóbal, crizzlycruz, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, KOOORAY, kscheel, kyokohunter, litlemoran, LovelyA72, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, sillyhatday, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, Timville, twitnic, velipso, Veund, voltagex, Voultar, wickawack, Wkr, x7l7j8cc, xactoes, yosoo, Zeii, Zelante, zvxr
## DISCLAIMER

View File

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