mirror of
https://github.com/lesserkuma/FlashGBX.git
synced 2026-04-25 07:57:25 -05:00
4.1
This commit is contained in:
parent
c8cd8ed340
commit
3f71efac47
|
|
@ -1,4 +1,10 @@
|
|||
# Release notes
|
||||
### v4.1 (released 2024-07-14)
|
||||
- Added support for M36XXX_32A_EARTH with M36L0R8060T *(thanks inYourBackline)*
|
||||
- Fixed a bug with Game Boy Advance Real Time Clock register saving *(thanks Sonikks)*
|
||||
- Added support for Development AGB Cartridge 64M Flash, E201629 (128M, with 4× LH28F320BJE) *(thanks Squiddy)*
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
### v4.0.1 (released 2024-06-30)
|
||||
- Bug fixes *(thanks marv17, RibShark)*
|
||||
|
||||
|
|
|
|||
|
|
@ -731,7 +731,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
msg = "This software is being developed by Lesserkuma as a hobby project. There is no affiliation with Nintendo or any other company. This software is provided as-is and the developer is not responsible for any damage that is caused by the use of it. Use at your own risk!<br><br>"
|
||||
msg += f"© 2020–{datetime.datetime.now().year} Lesserkuma<br>"
|
||||
msg += "• Website: <a href=\"https://github.com/lesserkuma/FlashGBX\">https://github.com/lesserkuma/FlashGBX</a><br><br>"
|
||||
msg += "Acknowledgments and Contributors:<br>2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr"
|
||||
msg += "Acknowledgments and Contributors:<br>2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, inYourBackline, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Sonikks, Squiddy, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr"
|
||||
QtWidgets.QMessageBox.information(self, "{:s} {:s}".format(APPNAME, VERSION), msg, QtWidgets.QMessageBox.Ok)
|
||||
|
||||
def OpenPath(self, path=None):
|
||||
|
|
@ -926,7 +926,7 @@ class FlashGBX_GUI(QtWidgets.QWidget):
|
|||
qt_app.processEvents()
|
||||
|
||||
messages = []
|
||||
last_msg = ""
|
||||
#last_msg = ""
|
||||
|
||||
# pylint: disable=global-variable-not-assigned
|
||||
global hw_devices
|
||||
|
|
|
|||
|
|
@ -420,14 +420,16 @@ class LK_Device(ABC):
|
|||
retries -= 1
|
||||
dprint("Retries left:", retries)
|
||||
|
||||
hp = 10
|
||||
hp = 20
|
||||
temp = 0
|
||||
while temp not in (1, 2) and hp > 0:
|
||||
self.DEVICE.reset_output_buffer()
|
||||
self.DEVICE.reset_input_buffer()
|
||||
self.DEVICE.write(b'\x00')
|
||||
temp = self._read(1)
|
||||
dprint("Current response:", temp)
|
||||
hp -= 1
|
||||
if hp == 0: break
|
||||
dprint("Current response:", temp, ", HP:", hp)
|
||||
#if hp == 0: break
|
||||
return False
|
||||
|
||||
def _write(self, data, wait=False):
|
||||
|
|
@ -533,9 +535,9 @@ class LK_Device(ABC):
|
|||
buffer.extend(struct.pack(">I", value))
|
||||
|
||||
if self.FW["fw_ver"] >= 12:
|
||||
self._try_write(buffer)
|
||||
return self._try_write(buffer)
|
||||
else:
|
||||
self._write(buffer)
|
||||
return self._write(buffer)
|
||||
|
||||
def _cart_read(self, address, length=0, agb_save_flash=False):
|
||||
if self.MODE == "DMG":
|
||||
|
|
@ -870,7 +872,8 @@ class LK_Device(ABC):
|
|||
self.SIGNAL = None
|
||||
|
||||
def Debug(self):
|
||||
# self.SetPin(["PIN_AUDIO"], True)
|
||||
# for i in range(0, 0x100000):
|
||||
# print(hex(i), self._set_fw_variable("ADDRESS", i), end="\r", flush=True)
|
||||
return
|
||||
|
||||
def ReadInfo(self, setPinsAsInputs=False, checkRtc=True):
|
||||
|
|
@ -2194,7 +2197,8 @@ class LK_Device(ABC):
|
|||
for j2 in range(0, len(d_swap)):
|
||||
for j in range(0, len(cfi_buffer)):
|
||||
cfi_buffer[j] = bitswap(cfi_buffer[j], d_swap[j2])
|
||||
with open("debug_cfi_2.bin", "wb") as f: f.write(cfi_buffer)
|
||||
if ".dev" in Util.VERSION_PEP440 or Util.DEBUG:
|
||||
with open("debug_cfi_d0d1+d6d7.bin", "wb") as f: f.write(cfi_buffer)
|
||||
else:
|
||||
cfi_buffer = None
|
||||
|
||||
|
|
@ -3333,6 +3337,8 @@ class LK_Device(ABC):
|
|||
rtc_buffer = self._read(8)
|
||||
if len(rtc_buffer) == 8 and _agb_gpio.HasRTC(rtc_buffer) is True:
|
||||
rtc_buffer = rtc_buffer[1:]
|
||||
rtc_buffer.append(_agb_gpio.RTCReadStatus()) # 24h mode = 0x40, reset flag = 0x80
|
||||
rtc_buffer.extend(struct.pack("<Q", int(time.time())))
|
||||
else:
|
||||
rtc_buffer = None
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -1769,9 +1769,8 @@ class AGB_GPIO:
|
|||
])
|
||||
|
||||
# Add timestamp of backup time
|
||||
ts = int(time.time())
|
||||
buffer.append(self.RTCReadStatus()) # 24h mode = 0x40, reset flag = 0x80
|
||||
buffer.extend(struct.pack("<Q", ts))
|
||||
buffer.extend(struct.pack("<Q", int(time.time())))
|
||||
|
||||
dprint(' '.join(format(x, '02X') for x in buffer))
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ from enum import Enum
|
|||
|
||||
# Common constants
|
||||
APPNAME = "FlashGBX"
|
||||
VERSION_PEP440 = "4.0.1"
|
||||
VERSION_PEP440 = "4.1"
|
||||
VERSION = "v{:s}".format(VERSION_PEP440)
|
||||
VERSION_TIMESTAMP = 1719742346
|
||||
VERSION_TIMESTAMP = 1720971150
|
||||
DEBUG = False
|
||||
DEBUG_LOG = []
|
||||
APP_PATH = ""
|
||||
|
|
|
|||
66
FlashGBX/config/fc_AGB_Dev_E201629_128M.txt
Normal file
66
FlashGBX/config/fc_AGB_Dev_E201629_128M.txt
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"Development AGB Cartridge 64M Flash, E201629 (128M)"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0xB0, 0x00, 0xE2, 0x00 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x1000000,
|
||||
"chip_erase_timeout":100,
|
||||
"wait_read_status_register":true,
|
||||
"set_irq_high":true,
|
||||
"reset_every":0x400000,
|
||||
"command_set":"SHARP",
|
||||
"commands":{
|
||||
"reset":[
|
||||
[ 0, 0x50 ],
|
||||
[ 0, 0xFF ]
|
||||
],
|
||||
"read_status_register":[
|
||||
[ 0, 0x70 ]
|
||||
],
|
||||
"read_identifier":[
|
||||
[ 0, 0x90 ]
|
||||
],
|
||||
"chip_erase":[
|
||||
[ 0, 0x30 ],
|
||||
[ 0, 0xD0 ],
|
||||
[ 0x400000, 0x30 ],
|
||||
[ 0x400000, 0xD0 ],
|
||||
[ 0x800000, 0x30 ],
|
||||
[ 0x800000, 0xD0 ],
|
||||
[ 0xC00000, 0x30 ],
|
||||
[ 0xC00000, 0xD0 ],
|
||||
[ 0, 0x70 ],
|
||||
[ 0x400000, 0x70 ],
|
||||
[ 0x800000, 0x70 ],
|
||||
[ 0xC00000, 0x70 ]
|
||||
],
|
||||
"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 ],
|
||||
[ 0, 0x80, 0xFF ],
|
||||
[ 0x400000, 0x80, 0xFF ],
|
||||
[ 0x800000, 0x80, 0xFF ],
|
||||
[ 0xC00000, 0x80, 0xFF ]
|
||||
],
|
||||
"single_write":[
|
||||
[ "PA", 0x70 ],
|
||||
[ "PA", 0x40 ],
|
||||
[ "PA", "PD" ]
|
||||
],
|
||||
"single_write_wait_for":[
|
||||
[ "PA", 0x80, 0xFF ],
|
||||
[ null, null, null ],
|
||||
[ null, null, null ]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"type":"AGB",
|
||||
"names":[
|
||||
"M36XXX_32A_EARTH with M36L0R8060B"
|
||||
"M36XXX_32A_EARTH with M36L0R8060B",
|
||||
"M36XXX_32A_EARTH with M36L0R8060T"
|
||||
],
|
||||
"flash_ids":[
|
||||
[ 0x20, 0x00, 0x0D, 0x88 ]
|
||||
[ 0x20, 0x00, 0x0D, 0x88 ],
|
||||
[ 0x20, 0x00, 0x0E, 0x88 ]
|
||||
],
|
||||
"voltage":3.3,
|
||||
"flash_size":0x2000000,
|
||||
|
|
|
|||
|
|
@ -32,7 +32,10 @@ class FirmwareUpdater():
|
|||
|
||||
with open(file, "rb") as f: temp = f.read().decode("UTF-8", "ignore")
|
||||
if not temp.startswith("UPDATE"):
|
||||
with open(file, "w", encoding="UTF-8") as f: f.write("UPDATE\r\n")
|
||||
with open(file, "wb") as f:
|
||||
temp = bytearray(b"UPDATE")
|
||||
temp += bytearray([0] * (256 - len(temp)))
|
||||
f.write(temp)
|
||||
hp = 30
|
||||
while hp > 0:
|
||||
if os.path.exists(path + "FIRMWARE.JR"): break
|
||||
|
|
@ -42,7 +45,12 @@ class FirmwareUpdater():
|
|||
fncSetStatus(text="Error: Couldn’t communicate with the Joey Jr device.")
|
||||
return 2
|
||||
|
||||
with open(file, "rb") as f: temp = f.read().decode("UTF-8", "ignore")
|
||||
try:
|
||||
with open(file, "rb") as f: temp = f.read().decode("UTF-8", "ignore")
|
||||
except FileNotFoundError:
|
||||
fncSetStatus(text="Error: Couldn’t open MODE.TXT file, please try again.")
|
||||
return 2
|
||||
|
||||
if not temp.startswith("UPDATE"):
|
||||
fncSetStatus(text="Error: Couldn’t enter UPDATE mode, please try again.")
|
||||
return 2
|
||||
|
|
@ -69,9 +77,18 @@ class FirmwareUpdater():
|
|||
except OSError:
|
||||
pass
|
||||
|
||||
time.sleep(3)
|
||||
if b"Joey Jr. Firmware" not in buffer:
|
||||
hp = 5
|
||||
while hp > 0:
|
||||
if not os.path.exists(path + "FIRMWARE.JR"): break
|
||||
time.sleep(1)
|
||||
hp -= 1
|
||||
if hp == 0:
|
||||
fncSetStatus(text="Error: Couldn’t verify, please try again.")
|
||||
return 2
|
||||
|
||||
fncSetStatus("Done.")
|
||||
time.sleep(1)
|
||||
time.sleep(2)
|
||||
|
||||
return True
|
||||
|
||||
|
|
@ -148,9 +165,9 @@ class FirmwareUpdater():
|
|||
fncSetStatus(text="Updating firmware... Do not unplug the device!", setProgress=percent)
|
||||
|
||||
dev.close()
|
||||
time.sleep(0.8)
|
||||
fncSetStatus("Done.", setProgress=100)
|
||||
time.sleep(1)
|
||||
fncSetStatus("Done.", setProgress=100)
|
||||
time.sleep(2)
|
||||
return 1
|
||||
|
||||
try:
|
||||
|
|
@ -302,9 +319,9 @@ try:
|
|||
self.lblDeviceNameResult.setText(self.DEV_NAME + " " + self.PCB_VER)
|
||||
self.lblDeviceFWVerResult.setText(self.FW_VER)
|
||||
|
||||
if platform.system() == 'Darwin':
|
||||
self.optFW_MSC.setVisible(False)
|
||||
self.lblFW_MSC_Blerb.setVisible(False)
|
||||
# if platform.system() == 'Darwin':
|
||||
# self.optFW_MSC.setVisible(False)
|
||||
# self.lblFW_MSC_Blerb.setVisible(False)
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
|
|
@ -446,8 +463,11 @@ try:
|
|||
elif ret == 4:
|
||||
if platform.system() == 'Darwin':
|
||||
self.SetStatus("No device found.", enableUI=True)
|
||||
text = "If your Joey Jr device is currently running the Drag'n'Drop firmware, please update the firmware on Windows or Linux, or use the standalone firmware updater."
|
||||
msgbox = QtWidgets.QMessageBox(parent=self, icon=QtWidgets.QMessageBox.Critical, windowTitle="FlashGBX", text=text, standardButtons=QtWidgets.QMessageBox.Ok)
|
||||
answer = msgbox.exec()
|
||||
return False
|
||||
answer = QtWidgets.QMessageBox.information(self, "FlashGBX", "If your Joey Jr device is currently running a Drag'n'Drop firmware, please continue and choose its <b>MODE.TXT</b> file.", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok)
|
||||
answer = QtWidgets.QMessageBox.information(self, "FlashGBX", "If your Joey Jr device is currently running the Drag'n'Drop firmware, please continue and choose its <b>MODE.TXT</b> file.", QtWidgets.QMessageBox.Ok | QtWidgets.QMessageBox.Cancel, QtWidgets.QMessageBox.Ok)
|
||||
if answer == QtWidgets.QMessageBox.Cancel:
|
||||
self.SetStatus("No device found.", enableUI=True)
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -320,3 +320,8 @@ class GbxDevice(LK_Device):
|
|||
except SerialException:
|
||||
pass
|
||||
return super().Close(cartPowerOff)
|
||||
|
||||
def SetTimeout(self, seconds=1):
|
||||
if seconds < 1: seconds = 1
|
||||
self.DEVICE_TIMEOUT = seconds
|
||||
self.DEVICE.timeout = self.DEVICE_TIMEOUT
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -146,8 +146,9 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- Game Boy Advance
|
||||
|
||||
- Action Replay Ultimate Codes (with SST39VF800A)
|
||||
- Development AGB Cartridge 64M Flash, E201629
|
||||
- Development AGB Cartridge 64M Flash S, E201843
|
||||
- Development AGB Cartridge 64M Flash, E201629¹
|
||||
- Development AGB Cartridge 64M Flash, E201629 (128M, with 4× LH28F320BJE)¹
|
||||
- Development AGB Cartridge 64M Flash S, E201843¹
|
||||
- Development AGB Cartridge 128M Flash S, E201850
|
||||
- Development AGB Cartridge 256M Flash S, E201868
|
||||
- DL9SEC GBA flashcart with TE28F128
|
||||
|
|
@ -297,7 +298,7 @@ Use this command in a Terminal or Command Prompt window to launch the installed
|
|||
- GA-07 with unlabeled flash chip
|
||||
- GE28F128W30 with 128W30B0
|
||||
- K5L2BX_32D_16D_V2 with K5L2833ATA
|
||||
- M36XXX_32A_EARTH with M36L0R8060B
|
||||
- M36XXX_32A_EARTH with M36L0R806
|
||||
- M36XXX_T32_32D_16D with M36L0R806
|
||||
- M5M29-39VF512 with M5M29HD528
|
||||
- M5M29G130AN (no PCB text)
|
||||
|
|
@ -341,7 +342,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, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr
|
||||
2358, 90sFlav, AcoVanConis, AdmirtheSableye, AlexiG, ALXCO-Hardware, AndehX, antPL, aronson, Ausar, bbsan, BennVenn, ccs21, chobby, ClassicOldSong, Cliffback, CodyWick13, Corborg, Cristóbal, crizzlycruz, Crystal, Därk, Davidish, DevDavisNunez, Diddy_Kong, djedditt, Dr-InSide, dyf2007, easthighNerd, EchelonPrime, edo999, Eldram, Ell, EmperorOfTigers, endrift, Erba Verde, ethanstrax, eveningmoose, Falknör, FerrantePescara, frarees, Frost Clock, gandalf1980, gboh, gekkio, Godan, Grender, HDR, Herax, Hiccup, hiks, howie0210, iamevn, Icesythe7, ide, inYourBackline, Jayro, Jenetrix, JFox, joyrider3774, JS7457, julgr, Kaede, kane159, KOOORAY, kscheel, kyokohunter, Leitplanke, litlemoran, LovelyA72, Lu, Luca DS, LucentW, manuelcm1, marv17, Merkin, metroid-maniac, Mr_V, olDirdey, orangeglo, paarongiroux, Paradoxical, Rairch, Raphaël BOICHOT, redalchemy, RetroGorek, RevZ, RibShark, s1cp, Satumox, Sgt.DoudouMiel, SH, Shinichi999, Sillyhatday, simonK, Sithdown, skite2001, Smelly-Ghost, Sonikks, Squiddy, Stitch, Super Maker, t5b6_de, Tauwasser, TheNFCookie, Timville, twitnic, velipso, Veund, voltagex, Voultar, Warez Waldo, wickawack, Winter1760, Wkr, x7l7j8cc, xactoes, xukkorz, yosoo, Zeii, Zelante, zipplet, Zoo, zvxr
|
||||
|
||||
## Third Party Notices and Licenses
|
||||
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -8,7 +8,7 @@ with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read(
|
|||
|
||||
setuptools.setup(
|
||||
name="FlashGBX",
|
||||
version="4.0.1",
|
||||
version="4.1",
|
||||
author="Lesserkuma",
|
||||
description="Reads and writes Game Boy and Game Boy Advance cartridge data",
|
||||
url="https://github.com/lesserkuma/FlashGBX",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user