FlashGBX 3.36__py3-none-any.whl → 4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- FlashGBX/FlashGBX.py +14 -7
- FlashGBX/FlashGBX_CLI.py +208 -28
- FlashGBX/FlashGBX_GUI.py +644 -209
- FlashGBX/Flashcart.py +195 -84
- FlashGBX/GBMemory.py +4 -5
- FlashGBX/LK_Device.py +4526 -0
- FlashGBX/Mapper.py +534 -356
- FlashGBX/RomFileAGB.py +92 -2
- FlashGBX/RomFileDMG.py +1 -1
- FlashGBX/UserInputDialog.py +20 -0
- FlashGBX/Util.py +116 -71
- FlashGBX/fw_GBFlash.py +426 -0
- FlashGBX/fw_GBxCartRW_v1_3.py +1 -1
- FlashGBX/fw_JoeyJr.py +472 -0
- FlashGBX/hw_GBFlash.py +244 -0
- FlashGBX/hw_GBxCartRW.py +200 -3715
- FlashGBX/hw_JoeyJr.py +309 -0
- FlashGBX/res/Third Party Notices.md +342 -0
- FlashGBX/res/config.zip +0 -0
- FlashGBX/res/fw_GBFlash.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_3.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4.zip +0 -0
- FlashGBX/res/fw_GBxCart_RW_v1_4a.zip +0 -0
- FlashGBX/res/fw_JoeyJr.zip +0 -0
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/METADATA +35 -14
- FlashGBX-4.0.dist-info/RECORD +43 -0
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/WHEEL +1 -1
- FlashGBX/hw_GBxCartRW_ofw.py +0 -2599
- FlashGBX-3.36.dist-info/RECORD +0 -36
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/LICENSE +0 -0
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/entry_points.txt +0 -0
- {FlashGBX-3.36.dist-info → FlashGBX-4.0.dist-info}/top_level.txt +0 -0
FlashGBX/Flashcart.py
CHANGED
|
@@ -99,6 +99,13 @@ class Flashcart:
|
|
|
99
99
|
else:
|
|
100
100
|
return ("buffer_write" in self.CONFIG["commands"])
|
|
101
101
|
|
|
102
|
+
def SupportsPageWrite(self):
|
|
103
|
+
buffer_size = self.GetBufferSize()
|
|
104
|
+
if buffer_size is False:
|
|
105
|
+
return False
|
|
106
|
+
else:
|
|
107
|
+
return ("page_write" in self.CONFIG["commands"])
|
|
108
|
+
|
|
102
109
|
def SupportsSingleWrite(self):
|
|
103
110
|
return ("single_write" in self.CONFIG["commands"])
|
|
104
111
|
|
|
@@ -133,6 +140,10 @@ class Flashcart:
|
|
|
133
140
|
if "flash_size" not in self.CONFIG: return default
|
|
134
141
|
return self.CONFIG["flash_size"]
|
|
135
142
|
|
|
143
|
+
def SetFlashSize(self, size):
|
|
144
|
+
if "flash_size" not in self.CONFIG: return
|
|
145
|
+
self.CONFIG["flash_size"] = size
|
|
146
|
+
|
|
136
147
|
def GetBufferSize(self):
|
|
137
148
|
if "buffer_size" in self.CONFIG:
|
|
138
149
|
return self.CONFIG["buffer_size"]
|
|
@@ -176,17 +187,17 @@ class Flashcart:
|
|
|
176
187
|
if full_reset and "power_cycle" in self.CONFIG:
|
|
177
188
|
self.CART_POWERCYCLE_FNCPTR()
|
|
178
189
|
time.sleep(0.001)
|
|
179
|
-
self.Unlock()
|
|
190
|
+
if self.Unlock() is False: return False
|
|
180
191
|
elif full_reset and "reset_every" in self.CONFIG and "flash_size" in self.CONFIG:
|
|
181
192
|
for j in range(0, self.CONFIG["flash_size"], self.CONFIG["reset_every"]):
|
|
182
193
|
if j >= max_address: break
|
|
183
194
|
dprint("reset_every @ 0x{:X}".format(j))
|
|
184
195
|
for command in self.CONFIG["commands"]["reset"]:
|
|
185
196
|
self.CartWrite([[j + command[0], command[1]]])
|
|
186
|
-
time.sleep(0.01)
|
|
197
|
+
#time.sleep(0.01)
|
|
187
198
|
elif "reset" in self.CONFIG["commands"]:
|
|
188
199
|
self.CartWrite(self.CONFIG["commands"]["reset"])
|
|
189
|
-
time.sleep(0.001)
|
|
200
|
+
#time.sleep(0.001)
|
|
190
201
|
|
|
191
202
|
def _VerifyFlashID(self, config):
|
|
192
203
|
if "read_identifier" not in config["commands"]: return (False, [])
|
|
@@ -234,7 +245,7 @@ class Flashcart:
|
|
|
234
245
|
if self.CFI is not None: return self.CFI
|
|
235
246
|
if "read_cfi" not in self.CONFIG["commands"]:
|
|
236
247
|
if self.CONFIG["_command_set"] == "INTEL":
|
|
237
|
-
self.CONFIG["commands"]["read_cfi"] =
|
|
248
|
+
self.CONFIG["commands"]["read_cfi"] = [ [ 0, 0x98 ] ]
|
|
238
249
|
elif self.CONFIG["_command_set"] == "AMD":
|
|
239
250
|
self.CONFIG["commands"]["read_cfi"] = [ [ 0xAA, 0x98 ] ]
|
|
240
251
|
|
|
@@ -361,82 +372,92 @@ class Flashcart:
|
|
|
361
372
|
self.Reset(full_reset=True)
|
|
362
373
|
return True
|
|
363
374
|
|
|
364
|
-
def SectorErase(self, pos=0, buffer_pos=0):
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
if addr == "SA+1": addr = pos + 1
|
|
378
|
-
if addr == "SA+2": addr = pos + 2
|
|
379
|
-
if addr == "SA+0x4000": addr = pos + 0x4000
|
|
380
|
-
if addr == "SA+0x7000": addr = pos + 0x7000
|
|
381
|
-
if not addr == None:
|
|
382
|
-
if we == "WR":
|
|
383
|
-
self.SET_WE_PIN_WR()
|
|
384
|
-
elif we == "AUDIO":
|
|
385
|
-
self.SET_WE_PIN_AUDIO()
|
|
386
|
-
self.CartWrite([[addr, data]])
|
|
387
|
-
if we is not None:
|
|
388
|
-
if self.DEFAULT_WE == "WR":
|
|
389
|
-
self.SET_WE_PIN_WR()
|
|
390
|
-
elif self.DEFAULT_WE == "AUDIO":
|
|
391
|
-
self.SET_WE_PIN_AUDIO()
|
|
392
|
-
|
|
393
|
-
if self.CONFIG["commands"]["sector_erase_wait_for"][i][0] != None:
|
|
394
|
-
addr = self.CONFIG["commands"]["sector_erase_wait_for"][i][0]
|
|
395
|
-
data = self.CONFIG["commands"]["sector_erase_wait_for"][i][1]
|
|
375
|
+
def SectorErase(self, pos=0, buffer_pos=0, skip=False):
|
|
376
|
+
if not skip:
|
|
377
|
+
self.Reset(full_reset=False)
|
|
378
|
+
if "sector_erase" not in self.CONFIG["commands"]: return False
|
|
379
|
+
if "sector_size" not in self.CONFIG: return False
|
|
380
|
+
for i in range(0, len(self.CONFIG["commands"]["sector_erase"])):
|
|
381
|
+
addr = self.CONFIG["commands"]["sector_erase"][i][0]
|
|
382
|
+
data = self.CONFIG["commands"]["sector_erase"][i][1]
|
|
383
|
+
if len(self.CONFIG["commands"]["sector_erase"][i]) > 2:
|
|
384
|
+
we = self.CONFIG["commands"]["sector_erase"][i][2]
|
|
385
|
+
else:
|
|
386
|
+
we = None
|
|
387
|
+
|
|
396
388
|
if addr == "SA": addr = pos
|
|
397
389
|
if addr == "SA+1": addr = pos + 1
|
|
398
390
|
if addr == "SA+2": addr = pos + 2
|
|
399
|
-
if addr == "SA+
|
|
400
|
-
if addr == "SA+
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
if
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
391
|
+
if addr == "SA+16384": addr = pos + 0x4000
|
|
392
|
+
if addr == "SA+28672": addr = pos + 0x7000
|
|
393
|
+
if addr == "SA+66": addr = pos + 0x42
|
|
394
|
+
if addr == "SA+132": addr = pos + 0x84
|
|
395
|
+
if not addr == None:
|
|
396
|
+
if we == "WR":
|
|
397
|
+
self.SET_WE_PIN_WR()
|
|
398
|
+
elif we == "AUDIO":
|
|
399
|
+
self.SET_WE_PIN_AUDIO()
|
|
400
|
+
self.CartWrite([[addr, data]])
|
|
401
|
+
if we is not None:
|
|
402
|
+
if self.DEFAULT_WE == "WR":
|
|
403
|
+
self.SET_WE_PIN_WR()
|
|
404
|
+
elif self.DEFAULT_WE == "AUDIO":
|
|
405
|
+
self.SET_WE_PIN_AUDIO()
|
|
406
|
+
|
|
407
|
+
if self.CONFIG["commands"]["sector_erase_wait_for"][i][0] != None:
|
|
408
|
+
addr = self.CONFIG["commands"]["sector_erase_wait_for"][i][0]
|
|
409
|
+
data = self.CONFIG["commands"]["sector_erase_wait_for"][i][1]
|
|
410
|
+
if addr == "SA": addr = pos
|
|
411
|
+
if addr == "SA+1": addr = pos + 1
|
|
412
|
+
if addr == "SA+2": addr = pos + 2
|
|
413
|
+
if addr == "SA+16384": addr = pos + 0x4000
|
|
414
|
+
if addr == "SA+28672": addr = pos + 0x7000
|
|
415
|
+
if addr == "SA+66": addr = pos + 0x42
|
|
416
|
+
if addr == "SA+132": addr = pos + 0x84
|
|
417
|
+
time.sleep(0.05)
|
|
418
|
+
timeout = 100
|
|
419
|
+
while True:
|
|
420
|
+
if "wait_read_status_register" in self.CONFIG and self.CONFIG["wait_read_status_register"] == True:
|
|
421
|
+
for j in range(0, len(self.CONFIG["commands"]["read_status_register"])):
|
|
422
|
+
sr_addr = self.CONFIG["commands"]["read_status_register"][j][0]
|
|
423
|
+
sr_data = self.CONFIG["commands"]["read_status_register"][j][1]
|
|
408
424
|
|
|
409
|
-
|
|
410
|
-
self.SET_WE_PIN_WR()
|
|
411
|
-
elif we == "AUDIO":
|
|
412
|
-
self.SET_WE_PIN_AUDIO()
|
|
413
|
-
self.CartWrite([[sr_addr, sr_data]])
|
|
414
|
-
if we is not None:
|
|
415
|
-
if self.DEFAULT_WE == "WR":
|
|
425
|
+
if we == "WR":
|
|
416
426
|
self.SET_WE_PIN_WR()
|
|
417
|
-
elif
|
|
427
|
+
elif we == "AUDIO":
|
|
418
428
|
self.SET_WE_PIN_AUDIO()
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
429
|
+
self.CartWrite([[sr_addr, sr_data]])
|
|
430
|
+
if we is not None:
|
|
431
|
+
if self.DEFAULT_WE == "WR":
|
|
432
|
+
self.SET_WE_PIN_WR()
|
|
433
|
+
elif self.DEFAULT_WE == "AUDIO":
|
|
434
|
+
self.SET_WE_PIN_AUDIO()
|
|
435
|
+
|
|
436
|
+
self.CartRead(addr, 2) # dummy read (fixes some bootlegs)
|
|
437
|
+
temp = self.CartRead(addr, 2)
|
|
438
|
+
if len(temp) != 2:
|
|
439
|
+
dprint("Communication error 1 in SectorErase():", temp)
|
|
440
|
+
return False
|
|
441
|
+
wait_for = self.CartRead(addr, 2)
|
|
442
|
+
if len(wait_for) != 2:
|
|
443
|
+
dprint("Communication error 2 in SectorErase():", temp)
|
|
444
|
+
return False
|
|
445
|
+
wait_for = struct.unpack("<H", wait_for)[0]
|
|
446
|
+
self.LAST_SR = wait_for
|
|
447
|
+
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)))
|
|
448
|
+
wait_for = wait_for & self.CONFIG["commands"]["sector_erase_wait_for"][i][2]
|
|
449
|
+
time.sleep(0.05)
|
|
450
|
+
timeout -= 1
|
|
451
|
+
if timeout < 1:
|
|
452
|
+
dprint(f"Timeout error in SectorErase(): 0x{self.LAST_SR:X}")
|
|
453
|
+
#self.PROGRESS_FNCPTR({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The sector erase attempt timed out. The last status register value was 0x{:X}.\n\nPlease make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.".format(self.LAST_SR), "abortable":False})
|
|
454
|
+
return False
|
|
455
|
+
if wait_for == data: break
|
|
456
|
+
self.PROGRESS_FNCPTR({"action":"SECTOR_ERASE", "sector_pos":buffer_pos, "time_start":time.time(), "abortable":True})
|
|
457
|
+
dprint("Done waiting!")
|
|
438
458
|
|
|
439
|
-
|
|
459
|
+
self.Reset(full_reset=False)
|
|
460
|
+
|
|
440
461
|
if isinstance(self.CONFIG["sector_size"], list):
|
|
441
462
|
self.CONFIG["sector_size"][self.SECTOR_POS][1] -= 1
|
|
442
463
|
if (self.CONFIG["sector_size"][self.SECTOR_POS][1] == 0) and (len(self.CONFIG["sector_size"]) > self.SECTOR_POS + 1):
|
|
@@ -450,11 +471,17 @@ class Flashcart:
|
|
|
450
471
|
else:
|
|
451
472
|
return self.CONFIG["sector_size"]
|
|
452
473
|
|
|
474
|
+
def HasBanks(self):
|
|
475
|
+
return "flash_bank_select_type" in self.CONFIG
|
|
476
|
+
|
|
453
477
|
def SelectBankROM(self, index):
|
|
454
478
|
if "flash_bank_select_type" not in self.CONFIG: return False
|
|
479
|
+
dprint(f"Setting flash bank to {index:d}")
|
|
455
480
|
if self.CONFIG["flash_bank_select_type"] == 1:
|
|
456
|
-
|
|
481
|
+
index = index & 0xF
|
|
457
482
|
self.CartWrite([[2, index << 4]], sram=True)
|
|
483
|
+
self.CartWrite([[3, 0x40]], sram=True)
|
|
484
|
+
self.CartWrite([[4, 0x00]], sram=True)
|
|
458
485
|
return True
|
|
459
486
|
elif self.CONFIG["flash_bank_select_type"] == 2: # Flash2Advance Ultra
|
|
460
487
|
bank1 = 0 if index < 4 else 0x10
|
|
@@ -478,16 +505,18 @@ class CFI:
|
|
|
478
505
|
magic = "{:s}{:s}{:s}".format(chr(buffer[0x20]), chr(buffer[0x22]), chr(buffer[0x24]))
|
|
479
506
|
info["d_swap"] = None
|
|
480
507
|
if magic == "QRY": # nothing swapped
|
|
481
|
-
info["d_swap"] = ( 0, 0 )
|
|
508
|
+
info["d_swap"] = [( 0, 0 )]
|
|
482
509
|
elif magic == "RQZ": # D0D1 swapped
|
|
483
|
-
info["d_swap"] = ( 0, 1 )
|
|
510
|
+
info["d_swap"] = [( 0, 1 )]
|
|
511
|
+
elif magic == "\x92\x91\x9A": # D0D1+D6D7 swapped
|
|
512
|
+
info["d_swap"] = [( 0, 1 ), ( 6, 7 )]
|
|
484
513
|
else:
|
|
485
514
|
return False
|
|
486
515
|
|
|
487
516
|
if info["d_swap"] is not None:
|
|
488
|
-
for
|
|
489
|
-
|
|
490
|
-
|
|
517
|
+
for j2 in range(0, len(info["d_swap"])):
|
|
518
|
+
for j in range(0, len(buffer)):
|
|
519
|
+
buffer[j] = bitswap(buffer[j], info["d_swap"][j2])
|
|
491
520
|
try:
|
|
492
521
|
info["flash_id"] = buffer[0:8]
|
|
493
522
|
info["magic"] = "{:s}{:s}{:s}".format(chr(buffer[0x20]), chr(buffer[0x22]), chr(buffer[0x24]))
|
|
@@ -576,7 +605,7 @@ class CFI:
|
|
|
576
605
|
return False
|
|
577
606
|
|
|
578
607
|
s = ""
|
|
579
|
-
if info["d_swap"] is not None and info["d_swap"] != ( 0, 0 ): s += "Swapped pins: {:s}\n".format(str(info["d_swap"]))
|
|
608
|
+
if info["d_swap"] is not None and info["d_swap"] != [( 0, 0 )]: s += "Swapped pins: {:s}\n".format(str(info["d_swap"]))
|
|
580
609
|
s += "Device size: 0x{:07X} ({:.2f} MB)\n".format(info["device_size"], info["device_size"] / 1024 / 1024)
|
|
581
610
|
s += "Voltage: {:.1f}–{:.1f} V\n".format(info["vdd_min"], info["vdd_max"])
|
|
582
611
|
s += "Single write: {:s}\n".format(str(info["single_write"]))
|
|
@@ -602,6 +631,88 @@ class CFI:
|
|
|
602
631
|
|
|
603
632
|
return info
|
|
604
633
|
|
|
634
|
+
class Flashcart_AGB_GBAMP(Flashcart):
|
|
635
|
+
def SectorErase(self, pos=0, buffer_pos=0, skip=False):
|
|
636
|
+
for i in range(0, 4):
|
|
637
|
+
sector = pos >> 13 << 16 | (pos & 0x1FFF) + (i * 4)
|
|
638
|
+
ret = super().SectorErase(sector, buffer_pos, skip)
|
|
639
|
+
if ret is False: break
|
|
640
|
+
return ret
|
|
641
|
+
|
|
642
|
+
def VerifyFlashID(self):
|
|
643
|
+
self.CART_POWERCYCLE_FNCPTR()
|
|
644
|
+
verified = False
|
|
645
|
+
self.Unlock()
|
|
646
|
+
rom = list(self.CartRead(0x1E8F << 1, 2) + self.CartRead(0x168F << 1, 2))
|
|
647
|
+
self.CartWrite(self.CONFIG["commands"]["read_identifier"], fast_write=True)
|
|
648
|
+
cart_flash_id = list(self.CartRead(0x1E8F << 1, 2) + self.CartRead(0x168F << 1, 2))
|
|
649
|
+
if rom != cart_flash_id and cart_flash_id == self.CONFIG["flash_ids"][0]:
|
|
650
|
+
self.CartWrite(self.CONFIG["commands"]["reset"], fast_write=True)
|
|
651
|
+
verified = True
|
|
652
|
+
dprint(verified, rom, cart_flash_id)
|
|
653
|
+
return (verified, cart_flash_id)
|
|
654
|
+
|
|
655
|
+
class Flashcart_DMG_BUNG_16M(Flashcart):
|
|
656
|
+
def SupportsSectorErase(self):
|
|
657
|
+
return False
|
|
658
|
+
|
|
659
|
+
def SupportsChipErase(self):
|
|
660
|
+
return True
|
|
661
|
+
|
|
662
|
+
def ChipErase(self, pos=0, buffer_pos=0, skip=False):
|
|
663
|
+
time_start = time.time()
|
|
664
|
+
if self.PROGRESS_FNCPTR is not None: self.PROGRESS_FNCPTR({"action":"ERASE", "time_start":time_start, "abortable":False})
|
|
665
|
+
|
|
666
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
667
|
+
self.CartWrite([[0x6AAA, 0xAA]], fast_write=True)
|
|
668
|
+
self.CartWrite([[0x2000, 0x01]], fast_write=False)
|
|
669
|
+
self.CartWrite([[0x5554, 0x55]], fast_write=True)
|
|
670
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
671
|
+
self.CartWrite([[0x6AAA, 0x80]], fast_write=True)
|
|
672
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
673
|
+
self.CartWrite([[0x6AAA, 0xAA]], fast_write=True)
|
|
674
|
+
self.CartWrite([[0x2000, 0x01]], fast_write=False)
|
|
675
|
+
self.CartWrite([[0x5554, 0x55]], fast_write=True)
|
|
676
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
677
|
+
self.CartWrite([[0x6AAA, 0x10]], fast_write=True)
|
|
678
|
+
|
|
679
|
+
lives = 10
|
|
680
|
+
while lives > 0:
|
|
681
|
+
sr = ord(self.CartRead(0))
|
|
682
|
+
self.LAST_SR = sr
|
|
683
|
+
dprint("Status Register Check: 0x{:X} & 0x{:X} == 0x{:X}? {:s}".format(sr, 0x80, 0x80, str((sr & 0x80) == 0x80)))
|
|
684
|
+
if (sr & 0x80) == 0x80: break
|
|
685
|
+
time.sleep(0.5)
|
|
686
|
+
lives -= 1
|
|
687
|
+
if lives == 0:
|
|
688
|
+
self.PROGRESS_FNCPTR({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Erasing the flash chip timed out. The last status register value was 0x{:X}.\n\nPlease make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.".format(self.LAST_SR), "abortable":False})
|
|
689
|
+
return False
|
|
690
|
+
|
|
691
|
+
self.Reset()
|
|
692
|
+
return True
|
|
693
|
+
|
|
694
|
+
def Reset(self, full_reset=None, max_address=None):
|
|
695
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
696
|
+
self.CartWrite([[0x6AAA, 0xAA]], fast_write=True)
|
|
697
|
+
self.CartWrite([[0x2000, 0x01]], fast_write=False)
|
|
698
|
+
self.CartWrite([[0x5554, 0x55]], fast_write=True)
|
|
699
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
700
|
+
self.CartWrite([[0x6AAA, 0xF0]], fast_write=True)
|
|
701
|
+
|
|
702
|
+
def VerifyFlashID(self):
|
|
703
|
+
rom = list(self.CartRead(0, 4))
|
|
704
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
705
|
+
self.CartWrite([[0x6AAA, 0xAA]], fast_write=True)
|
|
706
|
+
self.CartWrite([[0x2000, 0x01]], fast_write=False)
|
|
707
|
+
self.CartWrite([[0x5554, 0x55]], fast_write=True)
|
|
708
|
+
self.CartWrite([[0x2000, 0x02]], fast_write=False)
|
|
709
|
+
self.CartWrite([[0x6AAA, 0x90]], fast_write=True)
|
|
710
|
+
cart_flash_id = list(self.CartRead(0, 4))
|
|
711
|
+
if rom != cart_flash_id and cart_flash_id == self.CONFIG["flash_ids"][0]:
|
|
712
|
+
self.Reset()
|
|
713
|
+
verified = True
|
|
714
|
+
return (verified, cart_flash_id)
|
|
715
|
+
|
|
605
716
|
class Flashcart_DMG_MMSA(Flashcart):
|
|
606
717
|
def ReadCFI(self):
|
|
607
718
|
return False
|
|
@@ -618,7 +729,7 @@ class Flashcart_DMG_MMSA(Flashcart):
|
|
|
618
729
|
def EraseHiddenSector(self, buffer):
|
|
619
730
|
if self.PROGRESS_FNCPTR is not None: self.PROGRESS_FNCPTR({"action":"SECTOR_ERASE", "sector_pos":0, "time_start":time.time(), "abortable":False})
|
|
620
731
|
|
|
621
|
-
self.UnlockForWriting()
|
|
732
|
+
if self.UnlockForWriting() is False: return False
|
|
622
733
|
|
|
623
734
|
cmds = [
|
|
624
735
|
[ 0x120, 0x0F ],
|
|
@@ -738,13 +849,13 @@ class Flashcart_DMG_MMSA(Flashcart):
|
|
|
738
849
|
# Disable writes to MBC registers
|
|
739
850
|
cmds = [
|
|
740
851
|
[ 0x120, 0x10 ],
|
|
741
|
-
[ 0x13F,
|
|
852
|
+
[ 0x13F, 0xA5 ],
|
|
742
853
|
]
|
|
743
854
|
self.CartWrite(cmds)
|
|
744
855
|
# Undo Wakeup
|
|
745
856
|
cmds = [
|
|
746
857
|
[ 0x120, 0x08 ],
|
|
747
|
-
[ 0x13F,
|
|
858
|
+
[ 0x13F, 0xA5 ],
|
|
748
859
|
]
|
|
749
860
|
self.CartWrite(cmds)
|
|
750
861
|
return True
|
|
@@ -753,7 +864,7 @@ class Flashcart_DMG_MMSA(Flashcart):
|
|
|
753
864
|
time_start = time.time()
|
|
754
865
|
if self.PROGRESS_FNCPTR is not None: self.PROGRESS_FNCPTR({"action":"ERASE", "time_start":time_start, "abortable":False})
|
|
755
866
|
|
|
756
|
-
self.UnlockForWriting()
|
|
867
|
+
if self.UnlockForWriting() is False: return False
|
|
757
868
|
|
|
758
869
|
# Erase Chip
|
|
759
870
|
cmds = [
|
FlashGBX/GBMemory.py
CHANGED
|
@@ -11,10 +11,9 @@ class GBMemoryMap:
|
|
|
11
11
|
IS_MENU = False
|
|
12
12
|
|
|
13
13
|
def __init__(self, rom=None, oldmap=None):
|
|
14
|
+
self.MAP_DATA = bytearray([0xFF] * 0x80)
|
|
14
15
|
if rom is None: return
|
|
15
|
-
if rom
|
|
16
|
-
self.MAP_DATA = bytearray([0x00] * 0x80)
|
|
17
|
-
elif rom is not None:
|
|
16
|
+
if rom is not None:
|
|
18
17
|
self.ImportROM(rom)
|
|
19
18
|
if oldmap is not None:
|
|
20
19
|
self.MAP_DATA[0x70:0x78] = oldmap[0x70:0x78] # keep existing cart id
|
|
@@ -316,6 +315,6 @@ class GBMemoryMap:
|
|
|
316
315
|
return self.IS_MENU
|
|
317
316
|
|
|
318
317
|
def GetMapData(self):
|
|
319
|
-
if self.MAP_DATA == bytearray([0xFF] * 0x80):
|
|
320
|
-
|
|
318
|
+
#if self.MAP_DATA == bytearray([0xFF] * 0x80):
|
|
319
|
+
# return False
|
|
321
320
|
return self.MAP_DATA
|