Skip to content

Commit

Permalink
3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
lesserkuma committed Nov 15, 2021
1 parent 137b1a9 commit d2abd30
Show file tree
Hide file tree
Showing 29 changed files with 1,631 additions and 818 deletions.
Binary file modified .github/01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
# Release notes
### v3.0 (released 2021-11-15)
- Added support for the GBxCart RW v1.4a hardware revision
- Bundles GBxCart RW v1.4 firmware version R32+L3 (improves ROM writing speed for Development AGB Cartridge 256M Flash S, E201868)
- Added support for 0883_DRV with ES29LV160ET *(thanks RetroGorek)*
- Confirmed support for 2006_TSOP_64BALL_QFP48 with AL016J55FFAR2 *(thanks Sithdown)*
- Added support for GB-CART32K-A with SST39SF020A *(thanks Icesythe7)*
- Added support for 29LV Series Flash BOY with 29LV160DB *(thanks Luca DS)*
- Fixed a bug with reading ROMs of HuC-1 cartridges *(thanks Satumox)*
- When writing a save data file that is smaller than the selected save type suggests, repeats of the data will now be written instead of blank data; this can be useful for games like „Pokémon Pinball“ on a flash cartridge with larger SRAM/FRAM than required
- Confirmed support for SD007_TSOP_64BALL_SOP28 with unlabeled flash chip *(thanks marv17)*
- Added support for SD007_TSOP_64BALL_SOP28 with EN29LV160AB-70TCP *(thanks marv17)*
- Added support for SD007_TSOP_48BALL_V10 with 29DL32TF-70
- Improved the auto-detection of flash cartridges
- Fixed the auto-adjustment of Real Time Clock register values as the day counter was inaccurate
- Added the detection of a cartridge’s actual save type (requires save data to be present)

### v2.8 (released 2021-09-05)
- Added an option to fix wrong header checksums when writing a ROM *(thanks Voultar for the suggestion)*
- Fixed a bug with the auto-detect feature *(thanks Voultar)*
Expand Down
4 changes: 2 additions & 2 deletions FlashGBX/DataTransfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# FlashGBX
# Author: Lesserkuma (github.com/lesserkuma)

import sys, traceback
import traceback
import PySide2

class DataTransfer(PySide2.QtCore.QThread):
Expand Down Expand Up @@ -31,7 +31,7 @@ def run(self):

else:
self.FINISHED = False
self.CONFIG['port']._TransferData(self.CONFIG, self.updateProgress)
self.CONFIG['port'].TransferData(self.CONFIG, self.updateProgress)
self.FINISHED = True

except Exception as e:
Expand Down
389 changes: 244 additions & 145 deletions FlashGBX/FlashGBX_CLI.py

Large diffs are not rendered by default.

781 changes: 509 additions & 272 deletions FlashGBX/FlashGBX_GUI.py

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions FlashGBX/Flashcart.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ class Flashcart:
SECTOR_MAP = None
CFI = None

def __init__(self, config={}, cart_write_fncptr=None, cart_read_fncptr=None, progress_fncptr=None):
def __init__(self, config=None, cart_write_fncptr=None, cart_read_fncptr=None, progress_fncptr=None):
if config is None: config = {}
self.CART_WRITE_FNCPTR = cart_write_fncptr
self.CART_READ_FNCPTR = cart_read_fncptr
self.PROGRESS_FNCPTR = progress_fncptr
Expand Down Expand Up @@ -138,10 +139,11 @@ def Unlock(self):
self.CartWrite(self.CONFIG["commands"]["unlock"])
time.sleep(0.001)

def Reset(self, full_reset=False):
def Reset(self, full_reset=False, max_address=0x2000000):
#dprint(full_reset, "reset_every" in self.CONFIG)
if full_reset and "reset_every" in self.CONFIG:
for j in range(0, self.CONFIG["flash_size"], self.CONFIG["reset_every"]):
if j >= max_address: break
dprint("reset_every @ 0x{:X}".format(j))
for command in self.CONFIG["commands"]["reset"]:
self.CartWrite([[j, command[1]]])
Expand Down Expand Up @@ -307,7 +309,7 @@ def SectorErase(self, pos=0, buffer_pos=0):
except:
dprint("Warning: Sector map is smaller than expected.")
self.SECTOR_POS -= 1
self.CONFIG["sector_size"][self.SECTOR_POS][0]
#self.CONFIG["sector_size"][self.SECTOR_POS][0]
return sector_size
else:
return self.CONFIG["sector_size"]
Expand Down Expand Up @@ -437,7 +439,7 @@ def Parse(self, buffer):
s += "Buffered write: {:s}\n".format(str(info["buffer_write"]))
if info["chip_erase"]: s += "Chip erase: {:d}–{:d} ms\n".format(info["chip_erase_time_avg"], info["chip_erase_time_max"])
if info["sector_erase"]: s += "Sector erase: {:d}–{:d} ms\n".format(info["sector_erase_time_avg"], info["sector_erase_time_max"])
if info["tb_boot_sector"] is not False: s += "Sector order: {:s}\n".format(str(info["tb_boot_sector"]))
if info["tb_boot_sector"] is not False: s += "Sector flags: {:s}\n".format(str(info["tb_boot_sector"]))
pos = 0
oversize = False
s = s[:-1]
Expand Down
123 changes: 51 additions & 72 deletions FlashGBX/Mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ class DMG_MBC:
ROM_BANK_NUM = 0
CURRENT_ROM_BANK = 0

def __init__(self, args={}, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
def __init__(self, args=None, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
if args is None: args = {}
if "mbc" in args: self.MBC_ID = args["mbc"]
if "rom_banks" in args: self.ROM_BANK_NUM = args["rom_banks"]
self.CART_WRITE_FNCPTR = cart_write_fncptr
Expand All @@ -27,7 +28,8 @@ def __init__(self, args={}, cart_write_fncptr=None, cart_read_fncptr=None, clk_t
self.ROM_BANK_SIZE = 0x4000
self.RAM_BANK_SIZE = 0x2000

def GetInstance(self, args={}, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
def GetInstance(self, args=None, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
if args is None: args = {}
mbc_id = args["mbc"]
if mbc_id in (0x01, 0x02, 0x03): # 0x01:'MBC1', 0x02:'MBC1+SRAM', 0x03:'MBC1+SRAM+BATTERY',
return DMG_MBC1(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, clk_toggle_fncptr=clk_toggle_fncptr)
Expand Down Expand Up @@ -211,20 +213,31 @@ def HasRTC(self):
if self.MBC_ID != 16: return False
self.EnableRAM(enable=False)
self.EnableRAM(enable=True)
self.CartWrite([ [0x4000, 0x08] ])
#self.CartWrite([ [0x4000, 0x08] ])
self.LatchRTC()
ram1 = self.CartRead(0xA000, 0x10)
ram2 = ram1
t1 = time.time()
t2 = 0
while t2 < (t1 + 1):
self.LatchRTC()
ram2 = self.CartRead(0xA000, 0x10)
if ram1 != ram2: break
t2 = time.time()
dprint("RTC_S {:02X} != {:02X}?".format(ram1[0], ram2[0]), ram1 != ram2)
time.sleep(0.1)
return (ram1 != ram2)

skipped = True
for i in range(0x08, 0x0D):
self.CLK_TOGGLE_FNCPTR(60)
self.CartWrite([ [0x4000, i] ])
data = self.CartRead(0xA000, 0x800)
if data[0] in (0, 0xFF): continue
skipped = False
if data != bytearray([data[0]] * 0x800): return False
return skipped is False

#ram1 = self.CartRead(0xA000, 0x10)
#ram2 = ram1
#t1 = time.time()
#t2 = 0
#while t2 < (t1 + 1):
# self.LatchRTC()
# ram2 = self.CartRead(0xA000, 0x10)
# if ram1 != ram2: break
# t2 = time.time()
#dprint("RTC_S {:02X} != {:02X}?".format(ram1[0], ram2[0]), ram1 != ram2)
#time.sleep(0.1)
#return (ram1 != ram2)

def GetRTCBufferSize(self):
return 0x30
Expand Down Expand Up @@ -283,16 +296,18 @@ def WriteRTC(self, buffer, advance=False):
if timestamp_then < timestamp_now:
dt_then = datetime.datetime.fromtimestamp(timestamp_then)
dt_buffer1 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(2000, 1, 1, 0, 0, 0), "%Y-%m-%d %H:%M:%S")
dt_buffer2 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(2000, 1, 1, hours, minutes, seconds), "%Y-%m-%d %H:%M:%S")
dt_buffer2 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(2000, 1, 1, hours % 24, minutes % 60, seconds % 60), "%Y-%m-%d %H:%M:%S")
dt_buffer2 += datetime.timedelta(days=days)
rd = relativedelta(dt_now, dt_then)
dt_new = dt_buffer2 + rd
#print(dt_then, dt_now, dt_buffer2, dt_new, sep="\n")
dprint(dt_then, dt_now, dt_buffer1, dt_buffer2, dt_new, sep="\n")
seconds = dt_new.second
minutes = dt_new.minute
hours = dt_new.hour
temp = dt_new - dt_buffer1
days = temp.days
#temp = dt_new - dt_buffer1
#days = temp.days
temp = datetime.date.fromtimestamp(timestamp_now) - datetime.date.fromtimestamp(timestamp_then)
days = temp.days + days
if days >= 512:
carry = True
days = days % 512
Expand Down Expand Up @@ -341,43 +356,6 @@ def WriteRTC(self, buffer, advance=False):
self.CLK_TOGGLE_FNCPTR(50)
self.CartWrite([ [ 0x6000, 0x01 ] ])
time.sleep(0.1)
return
for i in range(0, 5):
self.CLK_TOGGLE_FNCPTR(50)
self.CartWrite([ [ 0x6000, 0x00 ] ])
self.CLK_TOGGLE_FNCPTR(50)
self.CartWrite([ [ 0x6000, 0x01 ] ])
time.sleep(0.1)
self.CLK_TOGGLE_FNCPTR(50)
self.CartWrite([ [ 0x4000, 0x0B ] ])
time.sleep(0.1)
dprint("Day = {:d}".format(self.CartRead(0xA000)))
self.CLK_TOGGLE_FNCPTR(50)
self.CartWrite([ [ 0x4000, 0x0A ] ])
time.sleep(0.1)
dprint("Hour = {:d}".format(self.CartRead(0xA000)))
self.CLK_TOGGLE_FNCPTR(50)
self.CartWrite([ [ 0x4000, 0x09 ] ])
time.sleep(0.1)
dprint("Minutes = {:d}".format(self.CartRead(0xA000)))
self.CLK_TOGGLE_FNCPTR(50)
self.CartWrite([ [ 0x4000, 0x08 ] ])
time.sleep(0.1)
dprint("Seconds = {:d}".format(self.CartRead(0xA000)))
time.sleep(0.5)
#import sys
#sys.exit()
return
for i in range(0x08, 0x0D):
self.CartWrite([ [0x4000, i] ])
data = struct.unpack("<I", buffer[(i-8)*4:(i-8)*4+4])[0] & 0xFF
dprint("Writing 0x{:02X} to 0x{:02X}".format(data, i))
self.CartWrite([ [0xA000, data] ])
self.CLK_TOGGLE_FNCPTR(1)
time.sleep(0.1)
#self.LatchRTC()
#self.CLK_TOGGLE_FNCPTR(1)
self.EnableRAM(enable=False)

class DMG_MBC5(DMG_MBC):
def GetName(self):
Expand Down Expand Up @@ -409,7 +387,8 @@ def SelectBankROM(self, index):
return (start_address, self.ROM_BANK_SIZE)

class DMG_MBC6(DMG_MBC):
def __init__(self, args={}, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
def __init__(self, args=None, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
if args is None: args = {}
super().__init__(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, clk_toggle_fncptr=None)
self.ROM_BANK_SIZE = 0x2000
self.RAM_BANK_SIZE = 0x1000
Expand Down Expand Up @@ -446,7 +425,7 @@ def SelectBankFlash(self, index):
start_address = 0x4000
return (start_address, self.ROM_BANK_SIZE)

def GetRAMBanks(self, size): # 0x108000
def GetRAMBanks(self, ram_size): # 0x108000
return 8 + 128

def SelectBankRAM(self, index):
Expand Down Expand Up @@ -737,7 +716,8 @@ class DMG_M161(DMG_MBC):
def GetName(self):
return "M161"

def __init__(self, args={}, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
def __init__(self, args=None, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
if args is None: args = {}
super().__init__(args=args, cart_write_fncptr=cart_write_fncptr, cart_read_fncptr=cart_read_fncptr, clk_toggle_fncptr=None)
self.ROM_BANK_SIZE = 0x8000
self.ROM_BANK_NUM = 8
Expand All @@ -753,7 +733,7 @@ def SelectBankROM(self, index):
self.CartWrite(commands)
return (0, 0x8000)

class DMG_HuC1(DMG_MBC1):
class DMG_HuC1(DMG_MBC5):
def GetName(self):
return "HuC-1"

Expand Down Expand Up @@ -834,23 +814,20 @@ def WriteRTC(self, buffer, advance=False):
timestamp_then = struct.unpack("<Q", buffer[-8:])[0]
timestamp_now = int(time.time())
dprint(hours, minutes, days)
#debug
#timestamp_now = 4102441140 # 2099-12-23 23:59:00
timestamp_now = time.time() + (3600 * 24 * 4095) + (3600 * 9)
dt_now = datetime.datetime.fromtimestamp(timestamp_now)
#debug
if timestamp_then < timestamp_now:
dt_then = datetime.datetime.fromtimestamp(timestamp_then)
dt_buffer1 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, 1, 1, 0, 0, 0), "%Y-%m-%d %H:%M:%S")
dt_buffer2 = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, 1, 1, hours, minutes, 0), "%Y-%m-%d %H:%M:%S")
dt_buffer2 += datetime.timedelta(days=days)
rd = relativedelta(dt_now, dt_then)
dt_new = dt_buffer2 + rd
#print(dt_then, dt_now, dt_buffer1, dt_buffer2, dt_new, sep="\n")
dprint(dt_then, dt_now, dt_buffer1, dt_buffer2, dt_new, sep="\n")
minutes = dt_new.minute
hours = dt_new.hour
temp = dt_new - dt_buffer1
days = temp.days
#temp = dt_new - dt_buffer1
#days = temp.days
temp = datetime.date.fromtimestamp(timestamp_now) - datetime.date.fromtimestamp(timestamp_then)
days = temp.days + days
dprint(minutes, hours, days)

total_minutes = 60 * hours + minutes
Expand Down Expand Up @@ -1012,7 +989,7 @@ def WriteRTC(self, buffer, advance=False):
timestamp_now = int(time.time())
if timestamp_then < timestamp_now:
dt_then = datetime.datetime.fromtimestamp(timestamp_then)
dt_buffer = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, months, days, hours, minutes, seconds), "%Y-%m-%d %H:%M:%S")
dt_buffer = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(1, months % 12, days % 31, hours % 24, minutes % 60, seconds % 60), "%Y-%m-%d %H:%M:%S")
rd = relativedelta(dt_now, dt_then)
dt_new = dt_buffer + rd
#print(dt_then, dt_now, dt_buffer, dt_new, sep="\n")
Expand Down Expand Up @@ -1089,7 +1066,8 @@ class AGB_GPIO:
RTC_WRITE_ALARM = 0x68
RTC_READ_ALARM = 0x69

def __init__(self, args={}, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
def __init__(self, args=None, cart_write_fncptr=None, cart_read_fncptr=None, clk_toggle_fncptr=None):
if args is None: args = {}
self.CART_WRITE_FNCPTR = cart_write_fncptr
self.CART_READ_FNCPTR = cart_read_fncptr
self.CLK_TOGGLE_FNCPTR = clk_toggle_fncptr
Expand Down Expand Up @@ -1222,12 +1200,13 @@ def ReadRTC(self):

# Add timestamp of backup time
ts = int(time.time())
buffer.extend(b'\x01') # 24h mode (TODO: read from status?)
buffer.extend(b'\x01') # 24h mode (TODO: read from cart?)
buffer.extend(struct.pack("<Q", ts))

dstr = ' '.join(format(x, '02X') for x in buffer)
dprint("[{:02X}] {:s}".format(int(len(dstr)/3) + 1, dstr))

# Digits are BCD (Binary Coded Decimal)
#[07] 00 01 27 05 06 30 20
#[07] 00 01 27 05 06 30 28
# "27 days, 06:51:55"
Expand Down Expand Up @@ -1263,7 +1242,7 @@ def WriteRTC(self, buffer, advance=False):
#debug
if timestamp_then < timestamp_now:
dt_then = datetime.datetime.fromtimestamp(timestamp_then)
dt_buffer = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(years + 2000, months, days, hours, minutes, seconds), "%Y-%m-%d %H:%M:%S")
dt_buffer = datetime.datetime.strptime("{:04d}-{:02d}-{:02d} {:02d}:{:02d}:{:02d}".format(years + 2000, months % 12, days % 31, hours % 60, minutes % 60, seconds % 60), "%Y-%m-%d %H:%M:%S")
rd = relativedelta(dt_now, dt_then)
dt_new = dt_buffer + rd
#print(dt_then, dt_now, dt_buffer, dt_new, sep="\n")
Expand Down
Loading

0 comments on commit d2abd30

Please sign in to comment.