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/hw_GBxCartRW_ofw.py
DELETED
|
@@ -1,2599 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# FlashGBX
|
|
3
|
-
# Author: Lesserkuma (github.com/lesserkuma)
|
|
4
|
-
# Partly based on work from Alex from insideGadgets (www.insidegadgets.com), code used with permission
|
|
5
|
-
# This code is used for official firmware of GBxCart v1.3 only and this code is pure chaos, sorry
|
|
6
|
-
# Refer to hw_GBxCartRW.py for the much cleaner rewrite (used for GBxCart RW v1.4 and firmware L1 on v1.3)
|
|
7
|
-
|
|
8
|
-
import time, math, struct, traceback, zlib, copy, hashlib, os, datetime, platform
|
|
9
|
-
import serial, serial.tools.list_ports
|
|
10
|
-
from serial import SerialException
|
|
11
|
-
from .RomFileDMG import RomFileDMG
|
|
12
|
-
from .RomFileAGB import RomFileAGB
|
|
13
|
-
from .Util import APPNAME, ANSI, dprint, bitswap, ParseCFI
|
|
14
|
-
from . import Util
|
|
15
|
-
|
|
16
|
-
class GbxDevice:
|
|
17
|
-
DEVICE_NAME = "GBxCart RW"
|
|
18
|
-
DEVICE_MIN_FW = 26
|
|
19
|
-
DEVICE_MAX_FW = 31
|
|
20
|
-
|
|
21
|
-
DEVICE_CMD = {
|
|
22
|
-
"CART_MODE":'C',
|
|
23
|
-
"GB_MODE":1,
|
|
24
|
-
"GBA_MODE":2,
|
|
25
|
-
# GB/GBC defines/commands
|
|
26
|
-
"SET_START_ADDRESS":'A',
|
|
27
|
-
"READ_ROM_RAM":'R',
|
|
28
|
-
"READ_ROM_4000H":'Q',
|
|
29
|
-
"WRITE_RAM":'W',
|
|
30
|
-
"SET_BANK":'B',
|
|
31
|
-
"SET_BANK_WITH_CS":'H',
|
|
32
|
-
"RESET_MBC":'-',
|
|
33
|
-
"GB_CART_MODE":'G',
|
|
34
|
-
"READ_EEPROM_MBC7":'~',
|
|
35
|
-
"WRITE_EEPROM_MBC7":'#',
|
|
36
|
-
# GBA defines/commands
|
|
37
|
-
"EEPROM_NONE":0,
|
|
38
|
-
"EEPROM_4KBIT":1,
|
|
39
|
-
"EEPROM_64KBIT":2,
|
|
40
|
-
"SRAM_FLASH_NONE":0,
|
|
41
|
-
"SRAM_FLASH_256KBIT":1,
|
|
42
|
-
"SRAM_FLASH_512KBIT":2,
|
|
43
|
-
"SRAM_FLASH_1MBIT":3,
|
|
44
|
-
"NOT_CHECKED":0,
|
|
45
|
-
"NO_FLASH":1,
|
|
46
|
-
"FLASH_FOUND":2,
|
|
47
|
-
"FLASH_FOUND_ATMEL":3,
|
|
48
|
-
"GBA_READ_ROM":'r',
|
|
49
|
-
"GBA_READ_ROM_256BYTE":'j',
|
|
50
|
-
"GBA_READ_ROM_8000H":'Z',
|
|
51
|
-
"GBA_READ_3DMEMORY":'}',
|
|
52
|
-
"GBA_READ_3DMEMORY_1000H":']',
|
|
53
|
-
"GBA_READ_SRAM":'m',
|
|
54
|
-
"GBA_WRITE_SRAM":'w',
|
|
55
|
-
"GBA_WRITE_ONE_BYTE_SRAM":'o',
|
|
56
|
-
"GBA_CART_MODE":'g',
|
|
57
|
-
"GBA_SET_EEPROM_SIZE":'S',
|
|
58
|
-
"GBA_READ_EEPROM":'e',
|
|
59
|
-
"GBA_WRITE_EEPROM":'p',
|
|
60
|
-
"GBA_FLASH_READ_ID":'i',
|
|
61
|
-
"GBA_FLASH_SET_BANK":'k',
|
|
62
|
-
"GBA_FLASH_4K_SECTOR_ERASE":'s',
|
|
63
|
-
"GBA_FLASH_WRITE_BYTE":'b',
|
|
64
|
-
"GBA_FLASH_WRITE_ATMEL":'a',
|
|
65
|
-
# Flash Cart commands
|
|
66
|
-
"GB_FLASH_WE_PIN":'P',
|
|
67
|
-
"WE_AS_AUDIO_PIN":'A',
|
|
68
|
-
"WE_AS_WR_PIN":'W',
|
|
69
|
-
"GB_FLASH_PROGRAM_METHOD":'E',
|
|
70
|
-
"GB_FLASH_PROGRAM_555":0,
|
|
71
|
-
"GB_FLASH_PROGRAM_AAA":1,
|
|
72
|
-
"GB_FLASH_PROGRAM_555_BIT01_SWAPPED":2,
|
|
73
|
-
"GB_FLASH_PROGRAM_AAA_BIT01_SWAPPED":3,
|
|
74
|
-
"GB_FLASH_PROGRAM_5555":4,
|
|
75
|
-
"GB_FLASH_PROGRAM_7AAA_BIT01_SWAPPED":5,
|
|
76
|
-
"GB_FLASH_WRITE_BYTE":'F',
|
|
77
|
-
"GB_FLASH_WRITE_64BYTE":'T',
|
|
78
|
-
"GB_FLASH_WRITE_256BYTE":'X',
|
|
79
|
-
"GB_FLASH_WRITE_UNBUFFERED_256BYTE":'{',
|
|
80
|
-
"GB_FLASH_WRITE_BUFFERED_32BYTE":'Y',
|
|
81
|
-
"GB_FLASH_BANK_1_COMMAND_WRITES":'N',
|
|
82
|
-
"GB_FLASH_WRITE_64BYTE_PULSE_RESET":'J',
|
|
83
|
-
"GB_FLASH_WRITE_INTEL_BUFFERED_32BYTE":'y',
|
|
84
|
-
"GBA_FLASH_CART_WRITE_BYTE":'n',
|
|
85
|
-
"GBA_FLASH_WRITE_64BYTE_SWAPPED_D0D1":'q',
|
|
86
|
-
"GBA_FLASH_WRITE_256BYTE_SWAPPED_D0D1":'t',
|
|
87
|
-
"GBA_FLASH_WRITE_256BYTE":'f',
|
|
88
|
-
"GBA_FLASH_WRITE_BUFFERED_256BYTE":'c',
|
|
89
|
-
"GBA_FLASH_WRITE_BUFFERED_256BYTE_SWAPPED_D0D1":'d',
|
|
90
|
-
"GBA_FLASH_WRITE_INTEL_64BYTE":'l',
|
|
91
|
-
"GBA_FLASH_WRITE_INTEL_1024BYTE_4050":'K',
|
|
92
|
-
"GBA_FLASH_WRITE_INTEL_256BYTE":';',
|
|
93
|
-
"GBA_FLASH_WRITE_INTEL_64BYTE_WORD":'u',
|
|
94
|
-
"GBA_FLASH_WRITE_INTEL_INTERLEAVED_256BYTE":'v',
|
|
95
|
-
"GBA_FLASH_WRITE_SHARP_64BYTE":'x',
|
|
96
|
-
# General commands
|
|
97
|
-
"SET_INPUT":'I',
|
|
98
|
-
"SET_OUTPUT":'O',
|
|
99
|
-
"SET_OUTPUT_LOW":'L',
|
|
100
|
-
"SET_OUTPUT_HIGH":'H',
|
|
101
|
-
"READ_INPUT":'D',
|
|
102
|
-
"RESET_COMMON_LINES":'M',
|
|
103
|
-
"READ_FIRMWARE_VERSION":'V',
|
|
104
|
-
"READ_PCB_VERSION":'h',
|
|
105
|
-
"VOLTAGE_3_3V":'3',
|
|
106
|
-
"VOLTAGE_5V":'5',
|
|
107
|
-
"SET_PINS_AS_INPUTS":':',
|
|
108
|
-
"RESET_AVR":'*',
|
|
109
|
-
"RESET_VALUE":0x7E5E1,
|
|
110
|
-
"XMAS_LEDS":'#',
|
|
111
|
-
"XMAS_VALUE":0x7690FCD,
|
|
112
|
-
"READ_BUFFER":0,
|
|
113
|
-
"USART_1_7M_SPEED":'>',
|
|
114
|
-
"CLK_HIGH":'K',
|
|
115
|
-
"CLK_LOW":'[',
|
|
116
|
-
"CART_PWR_ON":'/',
|
|
117
|
-
"CART_PWR_OFF":'.',
|
|
118
|
-
"QUERY_CART_PWR":']',
|
|
119
|
-
"QUERY_ADDR":'@',
|
|
120
|
-
"AUDIO_HIGH":'8',
|
|
121
|
-
"AUDIO_LOW":'9',
|
|
122
|
-
}
|
|
123
|
-
PCB_VERSIONS = {2:'v1.1/v1.2', 4:'v1.3', 90:'XMAS v1.0', 100:'Mini v1.0', 101:'Mini v1.0d'}
|
|
124
|
-
SUPPORTED_CARTS = {}
|
|
125
|
-
|
|
126
|
-
FW = []
|
|
127
|
-
FW_UPDATE_REQ = False
|
|
128
|
-
QBL = None
|
|
129
|
-
MODE = None
|
|
130
|
-
PORT = ''
|
|
131
|
-
DEVICE = None
|
|
132
|
-
WORKER = None
|
|
133
|
-
INFO = { "last_action":None, "dump_info":{} }
|
|
134
|
-
CANCEL = False
|
|
135
|
-
ERROR = False
|
|
136
|
-
CANCEL_ARGS = {}
|
|
137
|
-
SIGNAL = None
|
|
138
|
-
POS = 0
|
|
139
|
-
NO_PROG_UPDATE = False
|
|
140
|
-
FAST_READ = False
|
|
141
|
-
BAUDRATE = 1000000
|
|
142
|
-
WRITE_DELAY = False
|
|
143
|
-
READ_ERRORS = 0
|
|
144
|
-
|
|
145
|
-
def __init__(self):
|
|
146
|
-
pass
|
|
147
|
-
|
|
148
|
-
def Initialize(self, flashcarts, port=None, max_baud=1000000):
|
|
149
|
-
if self.IsConnected(): self.DEVICE.close()
|
|
150
|
-
|
|
151
|
-
dev = None
|
|
152
|
-
conn_msg = []
|
|
153
|
-
ports = []
|
|
154
|
-
if port is not None:
|
|
155
|
-
ports = [ port ]
|
|
156
|
-
else:
|
|
157
|
-
comports = serial.tools.list_ports.comports()
|
|
158
|
-
for i in range(0, len(comports)):
|
|
159
|
-
if comports[i].vid == 0x1A86 and comports[i].pid == 0x7523:
|
|
160
|
-
ports.append(comports[i].device)
|
|
161
|
-
#break
|
|
162
|
-
if len(ports) == 0: return False
|
|
163
|
-
|
|
164
|
-
for i in range(0, len(ports)):
|
|
165
|
-
try:
|
|
166
|
-
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
|
167
|
-
self.DEVICE = dev
|
|
168
|
-
if not self.LoadFirmwareVersion() and max_baud >= 1700000:
|
|
169
|
-
dev.close()
|
|
170
|
-
self.BAUDRATE = 1700000
|
|
171
|
-
dev = serial.Serial(ports[i], self.BAUDRATE, timeout=0.1)
|
|
172
|
-
self.DEVICE = dev
|
|
173
|
-
if not self.LoadFirmwareVersion():
|
|
174
|
-
dev.close()
|
|
175
|
-
self.DEVICE = None
|
|
176
|
-
self.BAUDRATE = 1000000
|
|
177
|
-
return False
|
|
178
|
-
|
|
179
|
-
elif len(self.FW) > 0 and self.FW[1] == 5 and self.BAUDRATE < 1700000 and max_baud >= 1700000:
|
|
180
|
-
pass
|
|
181
|
-
|
|
182
|
-
if self.DEVICE is None or not self.IsConnected() or self.FW == [] or self.FW[0] == b'' or self.QBL is False:
|
|
183
|
-
dev.close()
|
|
184
|
-
self.DEVICE = None
|
|
185
|
-
conn_msg.append([0, "Couldn’t communicate with the GBxCart RW device on port " + ports[i] + ". Please disconnect and reconnect the device, then try again."])
|
|
186
|
-
continue
|
|
187
|
-
|
|
188
|
-
if self.FW[0] == 0:
|
|
189
|
-
dev.close()
|
|
190
|
-
self.DEVICE = None
|
|
191
|
-
return False
|
|
192
|
-
elif (self.FW[1] == 100 and self.FW[0] < 26 and self.FW[0] != 20):
|
|
193
|
-
self.FW_UPDATE_REQ = True
|
|
194
|
-
elif (self.FW[1] == 90 and self.FW[0] < 30):
|
|
195
|
-
self.FW_UPDATE_REQ = True
|
|
196
|
-
elif (self.FW[1] in (2, 4, 90) and self.FW[0] < self.DEVICE_MAX_FW) or (self.FW[0] < self.DEVICE_MIN_FW):
|
|
197
|
-
self.FW_UPDATE_REQ = True
|
|
198
|
-
elif self.FW[0] < self.DEVICE_MAX_FW:
|
|
199
|
-
#conn_msg.append([1, "The GBxCart RW device on port " + ports[i] + " is running an older firmware version. Please consider updating to version R" + str(self.DEVICE_MAX_FW) + " to make use of the latest features.<br><br>Firmware updates are available at <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a>."])
|
|
200
|
-
pass
|
|
201
|
-
elif self.FW[0] > self.DEVICE_MAX_FW:
|
|
202
|
-
#conn_msg.append([0, "NOTE: The GBxCart RW device on port " + ports[i] + " is running a firmware version that is newer than what this version of FlashGBX was developed to work with."])
|
|
203
|
-
pass
|
|
204
|
-
|
|
205
|
-
if self.FW[1] not in self.PCB_VERSIONS.keys():
|
|
206
|
-
dev.close()
|
|
207
|
-
self.DEVICE = None
|
|
208
|
-
continue
|
|
209
|
-
|
|
210
|
-
if self.FW[1] not in (4, 5):
|
|
211
|
-
conn_msg.append([0, "{:s}Now running in Legacy Mode.\nNote that FlashGBX works with insideGadgets GBxCart RW v1.3 and newer.\nOlder revisions are not fully compatible! More info: https://www.gbxcart.com/{:s}".format(ANSI.YELLOW, ANSI.RESET)])
|
|
212
|
-
elif self.FW[1] == 4:
|
|
213
|
-
conn_msg.append([0, "{:s}Now running in Legacy Mode.\nFor full support install firmware version L1 from the “Tools” menu in GUI mode.{:s}".format(ANSI.YELLOW, ANSI.RESET)])
|
|
214
|
-
|
|
215
|
-
self.PORT = ports[i]
|
|
216
|
-
self.DEVICE.timeout = 1
|
|
217
|
-
|
|
218
|
-
# Load Flash Cartridge Handlers
|
|
219
|
-
self.UpdateFlashCarts(flashcarts)
|
|
220
|
-
|
|
221
|
-
# Stop after first found device
|
|
222
|
-
break
|
|
223
|
-
|
|
224
|
-
except SerialException as e:
|
|
225
|
-
if "Permission" in str(e):
|
|
226
|
-
conn_msg.append([3, "The GBxCart RW device on port " + ports[i] + " couldn’t be accessed. Make sure your user account has permission to use it and it’s not already in use by another application."])
|
|
227
|
-
else:
|
|
228
|
-
conn_msg.append([3, "A critical error occured while trying to access the GBxCart RW device on port " + ports[i] + ".\n\n" + str(e)])
|
|
229
|
-
continue
|
|
230
|
-
|
|
231
|
-
return conn_msg
|
|
232
|
-
|
|
233
|
-
def UpdateFlashCarts(self, flashcarts):
|
|
234
|
-
self.SUPPORTED_CARTS = {
|
|
235
|
-
"DMG":{ "Generic ROM Cartridge":"RETAIL" },
|
|
236
|
-
"AGB":{ "Generic ROM Cartridge":"RETAIL" }
|
|
237
|
-
}
|
|
238
|
-
for mode in flashcarts.keys():
|
|
239
|
-
for key in sorted(flashcarts[mode].keys(), key=str.casefold):
|
|
240
|
-
self.SUPPORTED_CARTS[mode][key] = flashcarts[mode][key]
|
|
241
|
-
|
|
242
|
-
def IsConnected(self):
|
|
243
|
-
if self.DEVICE is None: return False
|
|
244
|
-
if not self.DEVICE.isOpen(): return False
|
|
245
|
-
try:
|
|
246
|
-
while self.DEVICE.in_waiting > 0:
|
|
247
|
-
print("Clearing input buffer... ({:d})".format(self.DEVICE.in_waiting))
|
|
248
|
-
self.DEVICE.reset_input_buffer()
|
|
249
|
-
time.sleep(1)
|
|
250
|
-
self.DEVICE.reset_output_buffer()
|
|
251
|
-
self.LoadFirmwareVersion()
|
|
252
|
-
return True
|
|
253
|
-
except SerialException:
|
|
254
|
-
return False
|
|
255
|
-
|
|
256
|
-
def Close(self, cartPowerOff=False):
|
|
257
|
-
if self.IsConnected():
|
|
258
|
-
try:
|
|
259
|
-
if cartPowerOff:
|
|
260
|
-
self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
|
|
261
|
-
self.DEVICE.close()
|
|
262
|
-
except:
|
|
263
|
-
self.DEVICE = None
|
|
264
|
-
self.MODE = None
|
|
265
|
-
|
|
266
|
-
def GetName(self):
|
|
267
|
-
return "GBxCart RW"
|
|
268
|
-
|
|
269
|
-
def GetFirmwareVersion(self, more=False):
|
|
270
|
-
fw, _ = self.FW
|
|
271
|
-
return "R{:s}".format(str(fw))
|
|
272
|
-
|
|
273
|
-
def GetBaudRate(self):
|
|
274
|
-
return self.BAUDRATE
|
|
275
|
-
|
|
276
|
-
def ChangeBaudRate(self, _):
|
|
277
|
-
return
|
|
278
|
-
|
|
279
|
-
def GetPCBVersion(self):
|
|
280
|
-
_, pcb = self.FW
|
|
281
|
-
if pcb in self.PCB_VERSIONS:
|
|
282
|
-
return self.PCB_VERSIONS[pcb]
|
|
283
|
-
else:
|
|
284
|
-
return "(unknown revision)"
|
|
285
|
-
|
|
286
|
-
def GetFullName(self):
|
|
287
|
-
self.DEVICE_NAME = "{:s} {:s}".format(self.GetName(), self.GetPCBVersion())
|
|
288
|
-
return self.DEVICE_NAME
|
|
289
|
-
|
|
290
|
-
def GetFullNameExtended(self, more=False):
|
|
291
|
-
if more:
|
|
292
|
-
return "{:s} – Firmware {:s} on {:s}".format(self.GetFullName(), self.GetFirmwareVersion(), str(self.PORT))
|
|
293
|
-
else:
|
|
294
|
-
return "{:s} – Firmware {:s}".format(self.GetFullName(), self.GetFirmwareVersion())
|
|
295
|
-
|
|
296
|
-
def GetOfficialWebsite(self):
|
|
297
|
-
return "https://www.gbxcart.com/"
|
|
298
|
-
|
|
299
|
-
def SupportsFirmwareUpdates(self):
|
|
300
|
-
fw, pcb = self.FW
|
|
301
|
-
#return pcb == 4
|
|
302
|
-
return (pcb in (2, 4, 90, 100) and fw > 3)
|
|
303
|
-
|
|
304
|
-
def FirmwareUpdateAvailable(self):
|
|
305
|
-
fw, pcb = self.FW
|
|
306
|
-
#if pcb != 4: return False
|
|
307
|
-
if pcb not in (2, 4, 90, 100) and fw <= 3: return False
|
|
308
|
-
if (self.FW[1] == 100 and self.FW[0] >= 26): return False
|
|
309
|
-
if (self.FW[1] == 90 and self.FW[0] >= 30): return False
|
|
310
|
-
return fw < self.DEVICE_MAX_FW
|
|
311
|
-
|
|
312
|
-
def GetFirmwareUpdaterClass(self):
|
|
313
|
-
_, pcb = self.FW
|
|
314
|
-
if pcb in (2, 4, 90, 100):
|
|
315
|
-
try:
|
|
316
|
-
from . import fw_GBxCartRW_v1_3
|
|
317
|
-
return (None, fw_GBxCartRW_v1_3.FirmwareUpdaterWindow)
|
|
318
|
-
except:
|
|
319
|
-
return False
|
|
320
|
-
else:
|
|
321
|
-
return False
|
|
322
|
-
|
|
323
|
-
def GetPort(self):
|
|
324
|
-
return self.PORT
|
|
325
|
-
|
|
326
|
-
def GetFWBuildDate(self):
|
|
327
|
-
return ""
|
|
328
|
-
|
|
329
|
-
def LoadFirmwareVersion(self):
|
|
330
|
-
try:
|
|
331
|
-
self.DEVICE.reset_input_buffer()
|
|
332
|
-
self.DEVICE.reset_output_buffer()
|
|
333
|
-
self.write("0")
|
|
334
|
-
self.write(self.DEVICE_CMD["READ_PCB_VERSION"])
|
|
335
|
-
pcb = self.DEVICE.read(1)
|
|
336
|
-
if pcb == b'': return False
|
|
337
|
-
self.write(self.DEVICE_CMD["READ_FIRMWARE_VERSION"])
|
|
338
|
-
fw = self.DEVICE.read(1)
|
|
339
|
-
self.FW = [fw[0], pcb[0]]
|
|
340
|
-
if self.FW[1] in (2, 4) and self.FW[0] > 30: # check fw memory
|
|
341
|
-
self.set_number(0x21FF0, self.DEVICE_CMD["QUERY_ADDR"])
|
|
342
|
-
self.QBL = self.DEVICE.read(1)[0] == 84
|
|
343
|
-
return True
|
|
344
|
-
except:
|
|
345
|
-
self.FW = False
|
|
346
|
-
return False
|
|
347
|
-
|
|
348
|
-
def CanSetVoltageManually(self):
|
|
349
|
-
_, pcb = self.FW
|
|
350
|
-
if not pcb in (4, 100):
|
|
351
|
-
return True
|
|
352
|
-
else:
|
|
353
|
-
return False
|
|
354
|
-
|
|
355
|
-
def CanSetVoltageAutomatically(self):
|
|
356
|
-
_, pcb = self.FW
|
|
357
|
-
if pcb in (1, 2, 100):
|
|
358
|
-
return False
|
|
359
|
-
else:
|
|
360
|
-
return True
|
|
361
|
-
|
|
362
|
-
def CanPowerCycleCart(self):
|
|
363
|
-
_, pcb = self.FW
|
|
364
|
-
return pcb in (5, 6)
|
|
365
|
-
|
|
366
|
-
def GetSupprtedModes(self):
|
|
367
|
-
_, pcb = self.FW
|
|
368
|
-
if pcb in (100, 101):
|
|
369
|
-
return ["DMG"]
|
|
370
|
-
else:
|
|
371
|
-
return ["DMG", "AGB"]
|
|
372
|
-
|
|
373
|
-
def IsSupportedMbc(self, mbc):
|
|
374
|
-
return mbc in ( 0x00, 0x01, 0x02, 0x03, 0x10, 0x12, 0x13, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0xFC, 0xFE, 0xFF, 0x101, 0x103, 0x110 )
|
|
375
|
-
|
|
376
|
-
def IsSupported3dMemory(self):
|
|
377
|
-
return False
|
|
378
|
-
|
|
379
|
-
def IsClkConnected(self):
|
|
380
|
-
return False
|
|
381
|
-
|
|
382
|
-
def GetMode(self):
|
|
383
|
-
return self.MODE
|
|
384
|
-
|
|
385
|
-
def GetSupportedCartridgesDMG(self):
|
|
386
|
-
return (list(self.SUPPORTED_CARTS['DMG'].keys()), list(self.SUPPORTED_CARTS['DMG'].values()))
|
|
387
|
-
|
|
388
|
-
def GetSupportedCartridgesAGB(self):
|
|
389
|
-
return (list(self.SUPPORTED_CARTS['AGB'].keys()), list(self.SUPPORTED_CARTS['AGB'].values()))
|
|
390
|
-
|
|
391
|
-
def SetProgress(self, args):
|
|
392
|
-
if self.CANCEL and args["action"] not in ("ABORT", "FINISHED"): return
|
|
393
|
-
if "pos" in args: self.POS = args["pos"]
|
|
394
|
-
if args["action"] == "UPDATE_POS": self.INFO["transferred"] = args["pos"]
|
|
395
|
-
try:
|
|
396
|
-
self.SIGNAL.emit(args)
|
|
397
|
-
except AttributeError:
|
|
398
|
-
if self.SIGNAL is not None:
|
|
399
|
-
self.SIGNAL(args)
|
|
400
|
-
|
|
401
|
-
if args["action"] == "INITIALIZE":
|
|
402
|
-
self.POS = 0
|
|
403
|
-
elif args["action"] == "FINISHED":
|
|
404
|
-
self.POS = 0
|
|
405
|
-
self.SIGNAL = None
|
|
406
|
-
|
|
407
|
-
def SetWriteDelay(self, enable=True):
|
|
408
|
-
self.WRITE_DELAY = enable
|
|
409
|
-
|
|
410
|
-
def SetTimeout(self, seconds=1):
|
|
411
|
-
self.DEVICE.timeout = seconds
|
|
412
|
-
|
|
413
|
-
def wait_for_ack(self):
|
|
414
|
-
buffer = self.read(1)
|
|
415
|
-
if buffer == False:
|
|
416
|
-
stack = traceback.extract_stack()
|
|
417
|
-
stack = stack[len(stack)-2] # caller only
|
|
418
|
-
print("{:s}Waiting for confirmation from the device has timed out. (Called from {:s}(), line {:d}){:s}\n".format(ANSI.RED, stack.name, stack.lineno, ANSI.RESET))
|
|
419
|
-
self.CANCEL = True
|
|
420
|
-
self.ERROR = True
|
|
421
|
-
self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A timeout error occured while waiting for confirmation from the device. Please make sure that the cartridge contacts are clean, re-connect the device and try again from the beginning."}
|
|
422
|
-
return False
|
|
423
|
-
|
|
424
|
-
lives = 2
|
|
425
|
-
while buffer != b'1':
|
|
426
|
-
print("{:s}Waiting for confirmation from the device (buffer={:s})... {:s}".format(ANSI.YELLOW, str(buffer), ANSI.RESET))
|
|
427
|
-
lives -= 1
|
|
428
|
-
if lives < 1:
|
|
429
|
-
stack = traceback.extract_stack()
|
|
430
|
-
stack = stack[len(stack)-2] # caller only
|
|
431
|
-
print("{:s}Waiting for confirmation from the device has failed. (Called from {:s}(), line {:d}){:s}\n".format(ANSI.RED, stack.name, stack.lineno, ANSI.RESET))
|
|
432
|
-
self.CANCEL = True
|
|
433
|
-
self.ERROR = True
|
|
434
|
-
self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A critical error occured while waiting for confirmation from the device. Please make sure that the cartridge contacts are clean, re-connect the device and try again from the beginning."}
|
|
435
|
-
return False
|
|
436
|
-
else:
|
|
437
|
-
time.sleep(0.05)
|
|
438
|
-
buffer = self.read(1)
|
|
439
|
-
|
|
440
|
-
return True
|
|
441
|
-
|
|
442
|
-
def read(self, length=64, last=False, ask_next_bytes=True, max_bytes=64):
|
|
443
|
-
readlen = length
|
|
444
|
-
if readlen > 64: readlen = max_bytes
|
|
445
|
-
mbuffer = bytearray()
|
|
446
|
-
#dprint("read(length={:d}, last={:s}, ask_next_bytes={:s}, max_bytes={:d})".format(length, str(last), str(ask_next_bytes), max_bytes))
|
|
447
|
-
for i in range(0, length, readlen):
|
|
448
|
-
if self.DEVICE.in_waiting > 1000: dprint("Recv buffer used: {:d} bytes".format(self.DEVICE.in_waiting))
|
|
449
|
-
buffer = self.DEVICE.read(readlen)
|
|
450
|
-
if len(buffer) != readlen:
|
|
451
|
-
self.READ_ERRORS += 1
|
|
452
|
-
dprint("Received {:d} byte(s) instead of the expected {:d} bytes during iteration {:d}.".format(len(buffer), readlen, i))
|
|
453
|
-
self.write('0') # end
|
|
454
|
-
time.sleep(0.5)
|
|
455
|
-
while self.DEVICE.in_waiting > 0:
|
|
456
|
-
self.DEVICE.reset_input_buffer()
|
|
457
|
-
time.sleep(0.5)
|
|
458
|
-
self.DEVICE.reset_output_buffer()
|
|
459
|
-
return False
|
|
460
|
-
|
|
461
|
-
mbuffer += buffer
|
|
462
|
-
if not self.NO_PROG_UPDATE:
|
|
463
|
-
self.SetProgress({"action":"READ", "bytes_added":len(buffer)})
|
|
464
|
-
|
|
465
|
-
if ask_next_bytes and not (i + readlen >= length):
|
|
466
|
-
self.write('1') # ask for next bytes (continue message)
|
|
467
|
-
if (i + readlen) > length:
|
|
468
|
-
readlen = length - i
|
|
469
|
-
|
|
470
|
-
if (ask_next_bytes and last) or not ask_next_bytes:
|
|
471
|
-
self.write('0')
|
|
472
|
-
|
|
473
|
-
return mbuffer[:length]
|
|
474
|
-
|
|
475
|
-
def write(self, data, wait_for_ack=False):
|
|
476
|
-
if not isinstance(data, bytearray):
|
|
477
|
-
data = bytearray(data, 'ascii')
|
|
478
|
-
self.DEVICE.write(data)
|
|
479
|
-
self.DEVICE.flush()
|
|
480
|
-
if platform.system() == "Darwin" or self.WRITE_DELAY is True:
|
|
481
|
-
time.sleep(0.00125)
|
|
482
|
-
if wait_for_ack: return self.wait_for_ack()
|
|
483
|
-
|
|
484
|
-
def DetectCartridge(self, mbc=None, limitVoltage=False, checkSaveType=False):
|
|
485
|
-
self.SIGNAL = None
|
|
486
|
-
cart_type_id = 0
|
|
487
|
-
save_type = False
|
|
488
|
-
save_chip = None
|
|
489
|
-
sram_unstable = None
|
|
490
|
-
save_size = None
|
|
491
|
-
|
|
492
|
-
# Header
|
|
493
|
-
info = self.ReadInfo()
|
|
494
|
-
|
|
495
|
-
self.INFO["last_action"] = 0
|
|
496
|
-
self.INFO["action"] = None
|
|
497
|
-
|
|
498
|
-
(cart_types, cart_type_id, flash_id, cfi_s, cfi) = self.AutoDetectFlash(limitVoltage=limitVoltage)
|
|
499
|
-
return (info, save_size, save_type, save_chip, sram_unstable, cart_types, cart_type_id, cfi_s, cfi, flash_id)
|
|
500
|
-
|
|
501
|
-
def ReadRAM_TAMA5(self, rtc=False):
|
|
502
|
-
buffer = bytearray()
|
|
503
|
-
self.NO_PROG_UPDATE = True
|
|
504
|
-
|
|
505
|
-
# Read save state
|
|
506
|
-
for i in range(0, 0x20):
|
|
507
|
-
self.cart_write(0xA001, 0x06, cs=True) # register select and address (high)
|
|
508
|
-
self.cart_write(0xA000, i >> 4 | 0x01 << 1, cs=True) # bit 0 = higher ram address, rest = command
|
|
509
|
-
self.cart_write(0xA001, 0x07, cs=True) # address (low)
|
|
510
|
-
self.cart_write(0xA000, i & 0x0F, cs=True) # bits 0-3 = lower ram address
|
|
511
|
-
self.cart_write(0xA001, 0x0D, cs=True) # data out (high)
|
|
512
|
-
data_h = self.ReadROM(0xA000, 64)[0]
|
|
513
|
-
self.cart_write(0xA001, 0x0C, cs=True) # data out (low)
|
|
514
|
-
data_l = self.ReadROM(0xA000, 64)[0]
|
|
515
|
-
data = ((data_h & 0xF) << 4) | (data_l & 0xF)
|
|
516
|
-
buffer.append(data)
|
|
517
|
-
self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":i+1})
|
|
518
|
-
|
|
519
|
-
# Read RTC state
|
|
520
|
-
if rtc:
|
|
521
|
-
for r in range(0, 0x10):
|
|
522
|
-
self.cart_write(0xA001, 0x04, cs=True) # set address
|
|
523
|
-
self.cart_write(0xA000, r, cs=True) # address
|
|
524
|
-
self.cart_write(0xA001, 0x06, cs=True) # register select
|
|
525
|
-
self.cart_write(0xA000, 0x04 << 1, cs=True) # rtc mode
|
|
526
|
-
self.cart_write(0xA001, 0x07, cs=True) # set access mode
|
|
527
|
-
self.cart_write(0xA000, 1, cs=True) # 1 = read
|
|
528
|
-
self.cart_write(0xA001, 0x0C, cs=True) # data out
|
|
529
|
-
data = self.ReadROM(0xA000, 64)[0]
|
|
530
|
-
buffer.append(data)
|
|
531
|
-
self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":0x21+r})
|
|
532
|
-
|
|
533
|
-
# Add timestamp of backup time (a future version may offer to auto-advance or edit the values)
|
|
534
|
-
ts = int(time.time())
|
|
535
|
-
buffer.extend(struct.pack("<Q", ts))
|
|
536
|
-
|
|
537
|
-
self.NO_PROG_UPDATE = False
|
|
538
|
-
return buffer
|
|
539
|
-
|
|
540
|
-
def WriteRAM_TAMA5(self, data, rtc=False):
|
|
541
|
-
self.NO_PROG_UPDATE = True
|
|
542
|
-
|
|
543
|
-
for i in range(0, 0x20):
|
|
544
|
-
self.cart_write(0xA001, 0x05, cs=True) # data in (high)
|
|
545
|
-
self.cart_write(0xA000, data[i] >> 4, cs=True)
|
|
546
|
-
self.cart_write(0xA001, 0x04, cs=True) # data in (low)
|
|
547
|
-
self.cart_write(0xA000, data[i] & 0xF, cs=True)
|
|
548
|
-
self.cart_write(0xA001, 0x06, cs=True) # register select and address (high)
|
|
549
|
-
self.cart_write(0xA000, i >> 4 | 0x00 << 1, cs=True) # bit 0 = higher ram address, rest = command
|
|
550
|
-
self.cart_write(0xA001, 0x07, cs=True) # address (low)
|
|
551
|
-
self.cart_write(0xA000, i & 0x0F, cs=True) # bits 0-3 = lower ram address
|
|
552
|
-
self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":i+1})
|
|
553
|
-
|
|
554
|
-
if rtc and bytearray(data[0x20:0x30]) != bytearray([0xFF] * 0x10):
|
|
555
|
-
for r in range(0, 0x10):
|
|
556
|
-
self.cart_write(0xA001, 0x04, cs=True) # set address
|
|
557
|
-
self.cart_write(0xA000, r, cs=True) # address
|
|
558
|
-
self.cart_write(0xA001, 0x05, cs=True) # set value to write
|
|
559
|
-
self.cart_write(0xA000, data[0x20+r], cs=True) # value
|
|
560
|
-
self.cart_write(0xA001, 0x06, cs=True) # register select
|
|
561
|
-
self.cart_write(0xA000, 0x04 << 1, cs=True) # rtc mode
|
|
562
|
-
self.cart_write(0xA001, 0x07, cs=True) # set access mode
|
|
563
|
-
self.cart_write(0xA000, 0, cs=True) # 0 = write
|
|
564
|
-
self.SetProgress({"action":"UPDATE_POS", "abortable":False, "pos":0x21+r})
|
|
565
|
-
|
|
566
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":0x30})
|
|
567
|
-
self.NO_PROG_UPDATE = False
|
|
568
|
-
|
|
569
|
-
def ReadROM(self, offset, length, set_address=True, agb_3dmemory=False):
|
|
570
|
-
reqlen = length
|
|
571
|
-
if length < 64: length = 64
|
|
572
|
-
buffer = False
|
|
573
|
-
lives = 5
|
|
574
|
-
dprint("ReadROM(offset=0x{:X}, length=0x{:X}, set_address={:s}) fast_read_mode={:s}".format(offset, length, str(set_address), str(self.FAST_READ)))
|
|
575
|
-
while buffer == False:
|
|
576
|
-
ask_next_bytes = True
|
|
577
|
-
max_bytes = 64
|
|
578
|
-
if self.MODE == "DMG":
|
|
579
|
-
if self.FAST_READ and length == 0x4000:
|
|
580
|
-
ask_next_bytes = False
|
|
581
|
-
max_bytes = 0x80
|
|
582
|
-
if set_address:
|
|
583
|
-
self.set_number(offset, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
584
|
-
self.set_mode(self.DEVICE_CMD["READ_ROM_4000H"])
|
|
585
|
-
else:
|
|
586
|
-
if set_address:
|
|
587
|
-
self.set_number(offset, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
588
|
-
self.set_mode(self.DEVICE_CMD["READ_ROM_RAM"])
|
|
589
|
-
buffer = self.read(length, last=True, ask_next_bytes=ask_next_bytes)
|
|
590
|
-
elif self.MODE == "AGB":
|
|
591
|
-
if agb_3dmemory and self.FAST_READ and length == 0x1000:
|
|
592
|
-
ask_next_bytes = False
|
|
593
|
-
max_bytes = 0x80
|
|
594
|
-
if set_address:
|
|
595
|
-
self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
596
|
-
self.set_mode(self.DEVICE_CMD["GBA_READ_3DMEMORY_1000H"])
|
|
597
|
-
elif agb_3dmemory and length == 0x200:
|
|
598
|
-
if set_address:
|
|
599
|
-
self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
600
|
-
self.set_mode(self.DEVICE_CMD["GBA_READ_3DMEMORY"])
|
|
601
|
-
elif self.FAST_READ and length == 0x10000:
|
|
602
|
-
ask_next_bytes = False
|
|
603
|
-
max_bytes = 0x80
|
|
604
|
-
if set_address:
|
|
605
|
-
self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
606
|
-
self.set_mode(self.DEVICE_CMD["GBA_READ_ROM_8000H"])
|
|
607
|
-
else:
|
|
608
|
-
if set_address:
|
|
609
|
-
self.set_number(math.floor(offset / 2), self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
610
|
-
self.set_mode(self.DEVICE_CMD["GBA_READ_ROM"])
|
|
611
|
-
buffer = self.read(length, last=True, ask_next_bytes=ask_next_bytes, max_bytes=max_bytes)
|
|
612
|
-
|
|
613
|
-
if buffer == False:
|
|
614
|
-
if lives == 0:
|
|
615
|
-
self.CANCEL = True
|
|
616
|
-
self.ERROR = True
|
|
617
|
-
if self.FAST_READ:
|
|
618
|
-
self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"An error occured while receiving data from the device. Please disable Fast Read Mode, re-connect the device and try again."}
|
|
619
|
-
else:
|
|
620
|
-
self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"An error occured while receiving data from the device. Please re-connect the device and try again."}
|
|
621
|
-
print("{:s}{:s}Couldn’t recover from the read error.{:s}".format(ANSI.CLEAR_LINE, ANSI.RED, ANSI.RESET), flush=True)
|
|
622
|
-
return False
|
|
623
|
-
elif lives != 5:
|
|
624
|
-
print("", flush=True)
|
|
625
|
-
print("{:s}{:s}Failed to receive 0x{:X} bytes at 0x{:X}. Retrying...{:s}".format(ANSI.CLEAR_LINE, ANSI.YELLOW, length, self.POS, ANSI.RESET), flush=True)
|
|
626
|
-
set_address = True
|
|
627
|
-
lives -= 1
|
|
628
|
-
|
|
629
|
-
if lives < 5:
|
|
630
|
-
print("{:s}└ The retry was successful!".format(ANSI.CLEAR_LINE), flush=True)
|
|
631
|
-
|
|
632
|
-
return bytearray(buffer[:reqlen])
|
|
633
|
-
|
|
634
|
-
def gbx_flash_write_address_byte(self, address, data):
|
|
635
|
-
dprint("gbx_flash_write_address_byte(address=0x{:X}, data=0x{:X})".format(address, data))
|
|
636
|
-
if self.MODE == "DMG":
|
|
637
|
-
return self.gb_flash_write_address_byte(address, data)
|
|
638
|
-
elif self.MODE == "AGB":
|
|
639
|
-
return self.gba_flash_write_address_byte(address, data)
|
|
640
|
-
|
|
641
|
-
def gba_flash_write_address_byte(self, address, data):
|
|
642
|
-
address = int(address / 2)
|
|
643
|
-
address = format(address, 'x')
|
|
644
|
-
buffer = self.DEVICE_CMD["GBA_FLASH_CART_WRITE_BYTE"] + address + '\x00'
|
|
645
|
-
self.write(buffer)
|
|
646
|
-
time.sleep(0.001)
|
|
647
|
-
data = format(data, 'x')
|
|
648
|
-
buffer = self.DEVICE_CMD["GBA_FLASH_CART_WRITE_BYTE"] + data + '\x00'
|
|
649
|
-
self.write(buffer)
|
|
650
|
-
time.sleep(0.001)
|
|
651
|
-
|
|
652
|
-
ack = self.wait_for_ack()
|
|
653
|
-
if ack == False:
|
|
654
|
-
self.CANCEL = True
|
|
655
|
-
self.ERROR = True
|
|
656
|
-
self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A critical error occured while trying to write the ROM. Please re-connect the device and try again from the beginning."}
|
|
657
|
-
return False
|
|
658
|
-
|
|
659
|
-
def gb_flash_write_address_byte(self, address, data):
|
|
660
|
-
address = format(address, 'x')
|
|
661
|
-
buffer = self.DEVICE_CMD["GB_FLASH_WRITE_BYTE"] + address + '\x00'
|
|
662
|
-
self.write(buffer)
|
|
663
|
-
buffer = format(data, 'x') + '\x00'
|
|
664
|
-
self.write(buffer)
|
|
665
|
-
|
|
666
|
-
ack = self.wait_for_ack()
|
|
667
|
-
if ack == False:
|
|
668
|
-
self.CANCEL = True
|
|
669
|
-
self.ERROR = True
|
|
670
|
-
self.CANCEL_ARGS = {"info_type":"msgbox_critical", "info_msg":"A critical error occured while trying to write a byte. Please re-connect the device and try again from the beginning."}
|
|
671
|
-
return False
|
|
672
|
-
|
|
673
|
-
def gbx_flash_write_data_bytes(self, command, data):
|
|
674
|
-
buffer = bytearray(command, "ascii") + bytearray(data)
|
|
675
|
-
self.write(buffer)
|
|
676
|
-
|
|
677
|
-
def cart_write(self, address, bank, cs=False):
|
|
678
|
-
dprint("cart_write(address={:s}, data={:s})".format(format(address, 'x'), format(bank, 'x')))
|
|
679
|
-
# Firmware check R26+
|
|
680
|
-
if cs and self.FW[0] >= 26:
|
|
681
|
-
cmd = self.DEVICE_CMD["SET_BANK_WITH_CS"]
|
|
682
|
-
else:
|
|
683
|
-
cmd = self.DEVICE_CMD["SET_BANK"]
|
|
684
|
-
|
|
685
|
-
address = format(address, 'x')
|
|
686
|
-
buffer = cmd + address + '\x00'
|
|
687
|
-
self.write(buffer)
|
|
688
|
-
time.sleep(0.005)
|
|
689
|
-
bank = format(bank, 'd')
|
|
690
|
-
buffer = cmd + bank + '\x00'
|
|
691
|
-
self.write(buffer)
|
|
692
|
-
time.sleep(0.005)
|
|
693
|
-
|
|
694
|
-
def set_mode(self, command):
|
|
695
|
-
dprint("set_mode(command={:s})".format(str(command)))
|
|
696
|
-
buffer = format(command, 's')
|
|
697
|
-
self.write(buffer)
|
|
698
|
-
|
|
699
|
-
def set_number(self, number, command):
|
|
700
|
-
number = int(number)
|
|
701
|
-
buffer = format(command, 's') + format(number, 'x') + '\x00'
|
|
702
|
-
self.write(buffer)
|
|
703
|
-
time.sleep(0.005)
|
|
704
|
-
|
|
705
|
-
def EnableRAM(self, mbc=1, enable=True):
|
|
706
|
-
if enable:
|
|
707
|
-
if mbc in (0x01, 0x02, 0x03, 0x101, 0x103, 0x10, 0x13, 0x110): # MBC1, MBC1M, MBC3, MBC30
|
|
708
|
-
self.cart_write(0x6000, 1)
|
|
709
|
-
self.cart_write(0x0000, 0x0A, cs=(mbc == 0xFD))
|
|
710
|
-
else:
|
|
711
|
-
if mbc == 0xFF: # HuC-1
|
|
712
|
-
self.cart_write(0x0000, 0x0E) # enabling IR disables RAM
|
|
713
|
-
else:
|
|
714
|
-
self.cart_write(0x0000, 0x00, cs=(mbc == 0xFD))
|
|
715
|
-
if mbc <= 4: self.cart_write(0x6000, 0)
|
|
716
|
-
time.sleep(0.2)
|
|
717
|
-
|
|
718
|
-
def SetBankROM(self, bank, mbc=0, bank_count=0):
|
|
719
|
-
dprint("SetBankROM(bank={:d}, mbc=0x{:X}, bank_count={:d})".format(bank, int(mbc), bank_count))
|
|
720
|
-
if mbc == 0 and bank_count == 0:
|
|
721
|
-
mbc = 0x19 # MBC5
|
|
722
|
-
|
|
723
|
-
if mbc in (0x01, 0x02, 0x03): # MBC1
|
|
724
|
-
dprint("└[MBC1] 0x6000=0x00, 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 5, bank & 0x1F))
|
|
725
|
-
#self.cart_write(0x6000, 0)
|
|
726
|
-
#self.cart_write(0x4000, bank >> 5)
|
|
727
|
-
#self.cart_write(0x2000, bank & 0x1F)
|
|
728
|
-
self.cart_write(0x6000, 1)
|
|
729
|
-
self.cart_write(0x2000, bank)
|
|
730
|
-
self.cart_write(0x4000, bank >> 5)
|
|
731
|
-
elif mbc in (0x101, 0x103): # MBC1M
|
|
732
|
-
self.cart_write(0x4000, bank >> 4)
|
|
733
|
-
if (bank < 10):
|
|
734
|
-
dprint("└[MBC1M] 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 4, bank & 0x1F))
|
|
735
|
-
self.cart_write(0x2000, bank & 0x1F)
|
|
736
|
-
else:
|
|
737
|
-
dprint("└[MBC1M] 0x4000=0x{:X}, 0x2000=0x{:X}".format(bank >> 4, 0x10 | (bank & 0x1F)))
|
|
738
|
-
self.cart_write(0x2000, 0x10 | (bank & 0x1F))
|
|
739
|
-
elif (mbc == 0 and bank_count > 256) or mbc in (0x19, 0x1A, 0x1B, 0x1C, 0x1E): # MBC5
|
|
740
|
-
dprint("└[MBC5] 0x2100=0x{:X}".format(bank & 0xFF))
|
|
741
|
-
self.cart_write(0x2100, (bank & 0xFF))
|
|
742
|
-
if bank == 0 or bank >= 256:
|
|
743
|
-
dprint("└[MBC5] 0x3000=0x{:X}".format((bank >> 8) & 0xFF))
|
|
744
|
-
self.cart_write(0x3000, ((bank >> 8) & 0xFF))
|
|
745
|
-
elif mbc in (0x0B, 0x0D): # MMM01
|
|
746
|
-
if bank % 0x20 == 0:
|
|
747
|
-
dprint("└[MMM01] RESET_MBC, 0x2000=0x{:X}".format(bank))
|
|
748
|
-
self.set_mode(self.DEVICE_CMD['RESET_MBC'])
|
|
749
|
-
self.wait_for_ack()
|
|
750
|
-
self.cart_write(0x2000, bank) # start from this ROM bank
|
|
751
|
-
self.cart_write(0x6000, 0x00) # 0x00 = 512 KB, 0x04 = 32 KB, 0x08 = 64 KB, 0x10 = 128 KB, 0x20 = 256 KB
|
|
752
|
-
self.cart_write(0x4000, 0x40) # RAM bank?
|
|
753
|
-
self.cart_write(0x0000, 0x00)
|
|
754
|
-
self.cart_write(0x0000, 0x40) # Enable mapping
|
|
755
|
-
dprint("└[MMM01] 0x2100=0x{:X}".format(((bank % 0x20) & 0xFF)))
|
|
756
|
-
self.cart_write(0x2100, ((bank % 0x20) & 0xFF))
|
|
757
|
-
elif mbc == 0xFD: # TAMA5
|
|
758
|
-
dprint("└[TAMA5] 0xA001=0x00, 0xA000=0x{:X}, 0xA001=0x01, 0xA000=0x{:X}".format(bank & 0x0F, bank >> 4))
|
|
759
|
-
self.cart_write(0xA001, 0x00, cs=True) # ROM bank (low)
|
|
760
|
-
self.cart_write(0xA000, bank & 0x0F, cs=True)
|
|
761
|
-
self.cart_write(0xA001, 0x01, cs=True) # ROM bank (high)
|
|
762
|
-
self.cart_write(0xA000, (bank >> 4) & 0x0F, cs=True)
|
|
763
|
-
elif mbc == 0xFF: # HuC-1
|
|
764
|
-
dprint("└[HuC-1] 0x2000=0x{:X}".format(bank & 0x3F))
|
|
765
|
-
self.cart_write(0x2000, (bank & 0x3F))
|
|
766
|
-
elif mbc == 0x104: # M161
|
|
767
|
-
dprint("└[M161] RESET_MBC, 0x4000=0x{:X}".format(bank & 0x7))
|
|
768
|
-
self.set_mode(self.DEVICE_CMD['RESET_MBC'])
|
|
769
|
-
self.wait_for_ack()
|
|
770
|
-
self.cart_write(0x4000, (bank & 0x7))
|
|
771
|
-
else: # MBC2, MBC3 and others
|
|
772
|
-
dprint("└[MBCx] 0x2100=0x{:X}".format(bank & 0xFF))
|
|
773
|
-
self.cart_write(0x2100, (bank & 0xFF))
|
|
774
|
-
|
|
775
|
-
def SetBankRAM(self, bank, mbc=0x19):
|
|
776
|
-
if mbc in (0x06, 0xFD): return # MBC2 or TAMA5
|
|
777
|
-
dprint("SetBankRAM(bank={:d}, mbc={:d})".format(bank, mbc))
|
|
778
|
-
dprint("└[MBC] 0x4000=0x{:X}".format(bank & 0xFF))
|
|
779
|
-
self.cart_write(0x4000, (bank & 0xFF))
|
|
780
|
-
|
|
781
|
-
def ReadFlashSaveMakerID(self):
|
|
782
|
-
makers = { 0x1F:"ATMEL", 0xBF:"SST/SANYO", 0xC2:"MACRONIX", 0x32:"PANASONIC", 0x62:"SANYO" }
|
|
783
|
-
self.set_mode(self.DEVICE_CMD["GBA_FLASH_READ_ID"])
|
|
784
|
-
time.sleep(0.02)
|
|
785
|
-
buffer = self.DEVICE.read(2)
|
|
786
|
-
if buffer[0] in makers.keys():
|
|
787
|
-
return makers[buffer[0]]
|
|
788
|
-
else:
|
|
789
|
-
return buffer[0]
|
|
790
|
-
|
|
791
|
-
def CartPowerOff(self):
|
|
792
|
-
return
|
|
793
|
-
|
|
794
|
-
def CartPowerOn(self):
|
|
795
|
-
return
|
|
796
|
-
|
|
797
|
-
def SetMode(self, mode):
|
|
798
|
-
if mode == "DMG":
|
|
799
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
800
|
-
self.MODE = "DMG"
|
|
801
|
-
elif mode == "AGB":
|
|
802
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
|
803
|
-
self.MODE = "AGB"
|
|
804
|
-
self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
805
|
-
self.CartPowerOn()
|
|
806
|
-
|
|
807
|
-
def AutoDetectFlash(self, limitVoltage=False):
|
|
808
|
-
flash_types = []
|
|
809
|
-
flash_type = 0
|
|
810
|
-
flash_id = None
|
|
811
|
-
|
|
812
|
-
if self.MODE == "DMG":
|
|
813
|
-
if limitVoltage:
|
|
814
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
|
815
|
-
else:
|
|
816
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
817
|
-
|
|
818
|
-
supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
|
|
819
|
-
for f in range(2, len(supported_carts)):
|
|
820
|
-
flashcart_meta = supported_carts[f]
|
|
821
|
-
if flash_id is not None:
|
|
822
|
-
if ("flash_ids" not in flashcart_meta) or (flash_id not in flashcart_meta["flash_ids"]):
|
|
823
|
-
continue
|
|
824
|
-
|
|
825
|
-
self.set_mode(self.DEVICE_CMD["GB_CART_MODE"])
|
|
826
|
-
if "flash_commands_on_bank_1" in flashcart_meta:
|
|
827
|
-
self.set_mode(self.DEVICE_CMD["GB_FLASH_BANK_1_COMMAND_WRITES"])
|
|
828
|
-
|
|
829
|
-
if flashcart_meta["write_pin"] == "WR":
|
|
830
|
-
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
|
831
|
-
self.set_mode(self.DEVICE_CMD["WE_AS_WR_PIN"])
|
|
832
|
-
elif flashcart_meta["write_pin"] in ("AUDIO", "VIN"):
|
|
833
|
-
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
|
834
|
-
self.set_mode(self.DEVICE_CMD["WE_AS_AUDIO_PIN"])
|
|
835
|
-
|
|
836
|
-
# Reset Flash
|
|
837
|
-
if "reset" in flashcart_meta["commands"]:
|
|
838
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
839
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
840
|
-
|
|
841
|
-
# Unlock Flash
|
|
842
|
-
if "unlock" in flashcart_meta["commands"]:
|
|
843
|
-
for i in range(0, len(flashcart_meta["commands"]["unlock"])):
|
|
844
|
-
addr = flashcart_meta["commands"]["unlock"][i][0]
|
|
845
|
-
data = flashcart_meta["commands"]["unlock"][i][1]
|
|
846
|
-
count = flashcart_meta["commands"]["unlock"][i][2]
|
|
847
|
-
for _ in range(0, count):
|
|
848
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
849
|
-
|
|
850
|
-
# Read Flash ID / Electronic Signature
|
|
851
|
-
if "flash_ids" in flashcart_meta:
|
|
852
|
-
if "read_identifier" in flashcart_meta["commands"]:
|
|
853
|
-
for i in range(0, len(flashcart_meta["commands"]["read_identifier"])):
|
|
854
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["read_identifier"][i][0], flashcart_meta["commands"]["read_identifier"][i][1])
|
|
855
|
-
buffer = self.ReadROM(0, 64)
|
|
856
|
-
flash_id_found = False
|
|
857
|
-
for i in range(0, len(flashcart_meta["flash_ids"])):
|
|
858
|
-
id = list(buffer[0:len(flashcart_meta["flash_ids"][i])])
|
|
859
|
-
if id in flashcart_meta["flash_ids"]:
|
|
860
|
-
flash_id = id
|
|
861
|
-
flash_id_found = True
|
|
862
|
-
if not flash_id_found and len(flashcart_meta["flash_ids"]) > 0:
|
|
863
|
-
pass
|
|
864
|
-
|
|
865
|
-
# Reset Flash
|
|
866
|
-
if "reset" in flashcart_meta["commands"]:
|
|
867
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
868
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
869
|
-
|
|
870
|
-
if flash_id_found:
|
|
871
|
-
flash_type = f
|
|
872
|
-
flash_types.append(flash_type)
|
|
873
|
-
|
|
874
|
-
elif self.MODE == "AGB":
|
|
875
|
-
supported_carts = list(self.SUPPORTED_CARTS['AGB'].values())
|
|
876
|
-
for f in range(2, len(supported_carts)):
|
|
877
|
-
flashcart_meta = supported_carts[f]
|
|
878
|
-
if flash_id is not None:
|
|
879
|
-
if ("flash_ids" not in flashcart_meta) or (flash_id not in flashcart_meta["flash_ids"]):
|
|
880
|
-
continue
|
|
881
|
-
|
|
882
|
-
# Unlock Flash
|
|
883
|
-
if "unlock" in flashcart_meta["commands"]:
|
|
884
|
-
for i in range(0, len(flashcart_meta["commands"]["unlock"])):
|
|
885
|
-
addr = flashcart_meta["commands"]["unlock"][i][0]
|
|
886
|
-
data_ = flashcart_meta["commands"]["unlock"][i][1]
|
|
887
|
-
count = flashcart_meta["commands"]["unlock"][i][2]
|
|
888
|
-
for _ in range(0, count):
|
|
889
|
-
self.gbx_flash_write_address_byte(addr, data_)
|
|
890
|
-
|
|
891
|
-
# Reset Flash
|
|
892
|
-
if "reset" in flashcart_meta["commands"]:
|
|
893
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
894
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
895
|
-
|
|
896
|
-
# Read Flash ID / Electronic Signature
|
|
897
|
-
if "flash_ids" in flashcart_meta:
|
|
898
|
-
if "read_identifier" in flashcart_meta["commands"]:
|
|
899
|
-
for i in range(0, len(flashcart_meta["commands"]["read_identifier"])):
|
|
900
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["read_identifier"][i][0], flashcart_meta["commands"]["read_identifier"][i][1])
|
|
901
|
-
buffer = self.ReadROM(0, 64)
|
|
902
|
-
flash_id_found = False
|
|
903
|
-
for i in range(0, len(flashcart_meta["flash_ids"])):
|
|
904
|
-
id = list(buffer[0:len(flashcart_meta["flash_ids"][i])])
|
|
905
|
-
if id in flashcart_meta["flash_ids"]:
|
|
906
|
-
flash_id = id
|
|
907
|
-
flash_id_found = True
|
|
908
|
-
if not flash_id_found and len(flashcart_meta["flash_ids"]) > 0:
|
|
909
|
-
pass
|
|
910
|
-
|
|
911
|
-
# Reset Flash
|
|
912
|
-
if "reset" in flashcart_meta["commands"]:
|
|
913
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
914
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
915
|
-
|
|
916
|
-
if flash_id_found:
|
|
917
|
-
flash_type = f
|
|
918
|
-
flash_types.append(flash_type)
|
|
919
|
-
|
|
920
|
-
# Check flash size
|
|
921
|
-
flash_type_id = 0
|
|
922
|
-
cfi_s = ""
|
|
923
|
-
cfi = None
|
|
924
|
-
if len(flash_types) > 0:
|
|
925
|
-
flash_type_id = flash_types[0]
|
|
926
|
-
if self.MODE == "DMG":
|
|
927
|
-
supp_flash_types = self.GetSupportedCartridgesDMG()
|
|
928
|
-
elif self.MODE == "AGB":
|
|
929
|
-
supp_flash_types = self.GetSupportedCartridgesAGB()
|
|
930
|
-
|
|
931
|
-
(flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage, cart_type=supp_flash_types[1][flash_type_id])
|
|
932
|
-
if "flash_size" in supp_flash_types[1][flash_types[0]]:
|
|
933
|
-
size = supp_flash_types[1][flash_types[0]]["flash_size"]
|
|
934
|
-
size_undetected = False
|
|
935
|
-
for i in range(0, len(flash_types)):
|
|
936
|
-
if "flash_size" in supp_flash_types[1][flash_types[i]]:
|
|
937
|
-
if size != supp_flash_types[1][flash_types[i]]["flash_size"]:
|
|
938
|
-
size_undetected = True
|
|
939
|
-
|
|
940
|
-
if size_undetected:
|
|
941
|
-
if isinstance(cfi, dict) and "device_size" in cfi:
|
|
942
|
-
for i in range(0, len(flash_types)):
|
|
943
|
-
if cfi['device_size'] == supp_flash_types[1][flash_types[i]]["flash_size"]:
|
|
944
|
-
flash_type_id = flash_types[i]
|
|
945
|
-
size_undetected = False
|
|
946
|
-
break
|
|
947
|
-
|
|
948
|
-
else:
|
|
949
|
-
(flash_id, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=limitVoltage)
|
|
950
|
-
|
|
951
|
-
if self.MODE == "DMG" and not flash_id_found:
|
|
952
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
953
|
-
|
|
954
|
-
return (flash_types, flash_type_id, flash_id, cfi_s, cfi)
|
|
955
|
-
#return flash_types
|
|
956
|
-
|
|
957
|
-
def CheckFlashChip(self, limitVoltage=False, cart_type=None):
|
|
958
|
-
flash_id_lines = []
|
|
959
|
-
flash_commands = [
|
|
960
|
-
{ 'read_cfi':[[0x555, 0x98]], 'read_identifier':[[ 0x555, 0xAA ], [ 0x2AA, 0x55 ], [ 0x555, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
|
|
961
|
-
{ 'read_cfi':[[0x5555, 0x98]], 'read_identifier':[[ 0x5555, 0xAA ], [ 0x2AAA, 0x55 ], [ 0x5555, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
|
|
962
|
-
{ 'read_cfi':[[0xAA, 0x98]], 'read_identifier':[[ 0xAAA, 0xAA ], [ 0x555, 0x55 ], [ 0xAAA, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
|
|
963
|
-
{ 'read_cfi':[[0xAAA, 0x98]], 'read_identifier':[[ 0xAAA, 0xAA ], [ 0x555, 0x55 ], [ 0xAAA, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
|
|
964
|
-
{ 'read_cfi':[[0xAAAA, 0x98]], 'read_identifier':[[ 0xAAAA, 0xAA ], [ 0x5555, 0x55 ], [ 0xAAAA, 0x90 ]], 'reset':[[ 0x0, 0xF0 ]] },
|
|
965
|
-
{ 'read_cfi':[[0x4555, 0x98]], 'read_identifier':[[ 0x4555, 0xAA ], [ 0x4AAA, 0x55 ], [ 0x4555, 0x90 ]], 'reset':[[ 0x4000, 0xF0 ]] },
|
|
966
|
-
{ 'read_cfi':[[0x7555, 0x98]], 'read_identifier':[[ 0x7555, 0xAA ], [ 0x7AAA, 0x55 ], [ 0x7555, 0x90 ]], 'reset':[[ 0x7000, 0xF0 ]] },
|
|
967
|
-
{ 'read_cfi':[[0x4AAA, 0x98]], 'read_identifier':[[ 0x4AAA, 0xAA ], [ 0x4555, 0x55 ], [ 0x4AAA, 0x90 ]], 'reset':[[ 0x4000, 0xF0 ]] },
|
|
968
|
-
{ 'read_cfi':[[0x7AAA, 0x98]], 'read_identifier':[[ 0x7AAA, 0xAA ], [ 0x7555, 0x55 ], [ 0x7AAA, 0x90 ]], 'reset':[[ 0x7000, 0xF0 ]] },
|
|
969
|
-
{ 'read_cfi':[[0, 0x98]], 'read_identifier':[[ 0, 0x90 ]], 'reset':[[ 0, 0xFF ]] },
|
|
970
|
-
]
|
|
971
|
-
|
|
972
|
-
check_buffer = self.ReadROM(0, 0x200)
|
|
973
|
-
d_swap = None
|
|
974
|
-
cfi_info = ""
|
|
975
|
-
rom_string = ""
|
|
976
|
-
for j in range(0, 8):
|
|
977
|
-
rom_string += "{:02X} ".format(check_buffer[j])
|
|
978
|
-
rom_string += "\n"
|
|
979
|
-
cfi = {'raw':b''}
|
|
980
|
-
|
|
981
|
-
if self.MODE == "DMG":
|
|
982
|
-
if limitVoltage:
|
|
983
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
|
984
|
-
else:
|
|
985
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
986
|
-
rom_string = "[ ROM ] " + rom_string
|
|
987
|
-
we_pins = [ "WR", "AUDIO" ]
|
|
988
|
-
else:
|
|
989
|
-
rom_string = "[ ROM ] " + rom_string
|
|
990
|
-
we_pins = [ None ]
|
|
991
|
-
|
|
992
|
-
for we in we_pins:
|
|
993
|
-
if "method" in cfi: break
|
|
994
|
-
for method in flash_commands:
|
|
995
|
-
if self.MODE == "DMG":
|
|
996
|
-
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
|
997
|
-
self.set_mode(self.DEVICE_CMD["WE_AS_" + we + "_PIN"])
|
|
998
|
-
|
|
999
|
-
for i in range(0, len(method['reset'])):
|
|
1000
|
-
self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
|
|
1001
|
-
for i in range(0, len(method['read_cfi'])):
|
|
1002
|
-
self.gbx_flash_write_address_byte(method['read_cfi'][i][0], method["read_cfi"][i][1])
|
|
1003
|
-
buffer = self.ReadROM(0, 0x400)
|
|
1004
|
-
for i in range(0, len(method['reset'])):
|
|
1005
|
-
self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
|
|
1006
|
-
if buffer == check_buffer: continue
|
|
1007
|
-
|
|
1008
|
-
magic = "{:s}{:s}{:s}".format(chr(buffer[0x20]), chr(buffer[0x22]), chr(buffer[0x24]))
|
|
1009
|
-
if magic == "QRY": # nothing swapped
|
|
1010
|
-
d_swap = ( 0, 0 )
|
|
1011
|
-
elif magic == "RQZ": # D0D1 swapped
|
|
1012
|
-
d_swap = ( 0, 1 )
|
|
1013
|
-
if d_swap is not None:
|
|
1014
|
-
for i in range(0, len(buffer)):
|
|
1015
|
-
buffer[i] = bitswap(buffer[i], d_swap)
|
|
1016
|
-
|
|
1017
|
-
cfi_parsed = ParseCFI(buffer)
|
|
1018
|
-
try:
|
|
1019
|
-
if d_swap is not None:
|
|
1020
|
-
dprint("CFI @ {:s}/{:X}/{:X}/{:s}".format(str(we), method['read_identifier'][0][0], bitswap(method['read_identifier'][0][1], d_swap), str(d_swap)))
|
|
1021
|
-
else:
|
|
1022
|
-
dprint("CFI @ {:s}/{:X}/{:X}/{:s}".format(str(we), method['read_identifier'][0][0], method['read_identifier'][0][1], str(d_swap)))
|
|
1023
|
-
dprint("└", cfi_parsed)
|
|
1024
|
-
except:
|
|
1025
|
-
pass
|
|
1026
|
-
|
|
1027
|
-
if cfi_parsed != False:
|
|
1028
|
-
cfi = cfi_parsed
|
|
1029
|
-
cfi["raw"] = buffer
|
|
1030
|
-
if Util.DEBUG:
|
|
1031
|
-
with open("debug_cfi.bin", "wb") as f: f.write(buffer)
|
|
1032
|
-
|
|
1033
|
-
#cfi["sha1"] = hashlib.sha1(buffer).hexdigest()
|
|
1034
|
-
cfi["bytes"] = ""
|
|
1035
|
-
for i in range(0, 0x400):
|
|
1036
|
-
cfi["bytes"] += "{:02X}".format(buffer[i])
|
|
1037
|
-
if self.MODE == "DMG": cfi["we"] = we
|
|
1038
|
-
cfi["method_id"] = flash_commands.index(method)
|
|
1039
|
-
|
|
1040
|
-
if d_swap is not None:
|
|
1041
|
-
for k in method.keys():
|
|
1042
|
-
for c in range(0, len(method[k])):
|
|
1043
|
-
if isinstance(method[k][c][1], int):
|
|
1044
|
-
method[k][c][1] = bitswap(method[k][c][1], d_swap)
|
|
1045
|
-
|
|
1046
|
-
# Flash ID
|
|
1047
|
-
for i in range(0, len(method['read_identifier'])):
|
|
1048
|
-
self.gbx_flash_write_address_byte(method['read_identifier'][i][0], method["read_identifier"][i][1])
|
|
1049
|
-
flash_id = self.ReadROM(0, 64)[0:8]
|
|
1050
|
-
if self.MODE == "DMG":
|
|
1051
|
-
method_string = "[" + we.ljust(5) + "/{:4X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
|
|
1052
|
-
else:
|
|
1053
|
-
method_string = "[{:6X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
|
|
1054
|
-
line_exists = False
|
|
1055
|
-
for i in range(0, len(flash_id_lines)):
|
|
1056
|
-
if method_string == flash_id_lines[i][0]: line_exists = True
|
|
1057
|
-
if not line_exists: flash_id_lines.append([method_string, flash_id])
|
|
1058
|
-
for i in range(0, len(method['reset'])):
|
|
1059
|
-
self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
|
|
1060
|
-
|
|
1061
|
-
cfi["method"] = method
|
|
1062
|
-
|
|
1063
|
-
if cart_type is not None: # reset cartridge if method is known
|
|
1064
|
-
flashcart_meta = copy.deepcopy(cart_type)
|
|
1065
|
-
if "reset" in flashcart_meta["commands"]:
|
|
1066
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
1067
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
1068
|
-
|
|
1069
|
-
if "method" in cfi:
|
|
1070
|
-
s = ""
|
|
1071
|
-
if d_swap is not None and d_swap != ( 0, 0 ): s += "Swapped pins: {:s}\n".format(str(d_swap))
|
|
1072
|
-
s += "Device size: 0x{:07X} ({:.2f} MB)\n".format(cfi["device_size"], cfi["device_size"] / 1024 / 1024)
|
|
1073
|
-
s += "Voltage: {:.1f}–{:.1f} V\n".format(cfi["vdd_min"], cfi["vdd_max"])
|
|
1074
|
-
s += "Single write: {:s}\n".format(str(cfi["single_write"]))
|
|
1075
|
-
if "buffer_size" in cfi:
|
|
1076
|
-
s += "Buffered write: {:s} ({:d} Bytes)\n".format(str(cfi["buffer_write"]), cfi["buffer_size"])
|
|
1077
|
-
else:
|
|
1078
|
-
s += "Buffered write: {:s}\n".format(str(cfi["buffer_write"]))
|
|
1079
|
-
if cfi["chip_erase"]: s += "Chip erase: {:d}–{:d} ms\n".format(cfi["chip_erase_time_avg"], cfi["chip_erase_time_max"])
|
|
1080
|
-
if cfi["sector_erase"]: s += "Sector erase: {:d}–{:d} ms\n".format(cfi["sector_erase_time_avg"], cfi["sector_erase_time_max"])
|
|
1081
|
-
if cfi["tb_boot_sector"] is not False: s += "Sector flags: {:s}\n".format(str(cfi["tb_boot_sector"]))
|
|
1082
|
-
pos = 0
|
|
1083
|
-
oversize = False
|
|
1084
|
-
s = s[:-1]
|
|
1085
|
-
for i in range(0, cfi['erase_sector_regions']):
|
|
1086
|
-
esb = cfi['erase_sector_blocks'][i]
|
|
1087
|
-
s += "\nRegion {:d}: 0x{:07X}–0x{:07X} @ 0x{:X} Bytes × {:d}".format(i+1, pos, pos+esb[2]-1, esb[0], esb[1])
|
|
1088
|
-
if oversize: s += " (alt)"
|
|
1089
|
-
pos += esb[2]
|
|
1090
|
-
if pos >= cfi['device_size']:
|
|
1091
|
-
pos = 0
|
|
1092
|
-
oversize = True
|
|
1093
|
-
#s += "\nSHA-1: {:s}".format(cfi["sha1"])
|
|
1094
|
-
cfi_info = s
|
|
1095
|
-
|
|
1096
|
-
if cfi['raw'] == b'':
|
|
1097
|
-
for we in we_pins:
|
|
1098
|
-
for method in flash_commands:
|
|
1099
|
-
for i in range(0, len(method['reset'])):
|
|
1100
|
-
self.gbx_flash_write_address_byte(method['reset'][i][0], method["reset"][i][1])
|
|
1101
|
-
for i in range(0, len(method['read_identifier'])):
|
|
1102
|
-
self.gbx_flash_write_address_byte(method['read_identifier'][i][0], method["read_identifier"][i][1])
|
|
1103
|
-
flash_id = self.ReadROM(0, 64)[0:8]
|
|
1104
|
-
for i in range(0, len(method['reset'])):
|
|
1105
|
-
self.gbx_flash_write_address_byte(method['reset'][i][0], method["reset"][i][1])
|
|
1106
|
-
|
|
1107
|
-
if flash_id != check_buffer[0:8]:
|
|
1108
|
-
if self.MODE == "DMG":
|
|
1109
|
-
method_string = "[" + we.ljust(5) + "/{:4X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
|
|
1110
|
-
else:
|
|
1111
|
-
method_string = "[{:6X}/{:2X}]".format(method['read_identifier'][0][0], method['read_identifier'][0][1])
|
|
1112
|
-
line_exists = False
|
|
1113
|
-
for i in range(0, len(flash_id_lines)):
|
|
1114
|
-
if method_string == flash_id_lines[i][0]: line_exists = True
|
|
1115
|
-
if not line_exists: flash_id_lines.append([method_string, flash_id])
|
|
1116
|
-
for i in range(0, len(method['reset'])):
|
|
1117
|
-
self.gbx_flash_write_address_byte(method['reset'][i][0], method['reset'][i][1])
|
|
1118
|
-
|
|
1119
|
-
if self.MODE == "DMG":
|
|
1120
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
1121
|
-
|
|
1122
|
-
if cart_type is not None: # reset cartridge if method is known
|
|
1123
|
-
flashcart_meta = copy.deepcopy(cart_type)
|
|
1124
|
-
if "reset_every" in flashcart_meta and "flash_size" in flashcart_meta:
|
|
1125
|
-
for j in range(0, flashcart_meta["flash_size"], flashcart_meta["reset_every"]):
|
|
1126
|
-
if j >= 0x2000000: break
|
|
1127
|
-
dprint("reset_every @ 0x{:X}".format(j))
|
|
1128
|
-
for command in flashcart_meta["commands"]["reset"]:
|
|
1129
|
-
self.gbx_flash_write_address_byte(j, command[1])
|
|
1130
|
-
time.sleep(0.01)
|
|
1131
|
-
elif "reset" in flashcart_meta["commands"]:
|
|
1132
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
1133
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
1134
|
-
|
|
1135
|
-
flash_id = ""
|
|
1136
|
-
for i in range(0, len(flash_id_lines)):
|
|
1137
|
-
flash_id += flash_id_lines[i][0] + " "
|
|
1138
|
-
for j in range(0, 8):
|
|
1139
|
-
flash_id += "{:02X} ".format(flash_id_lines[i][1][j])
|
|
1140
|
-
flash_id += "\n"
|
|
1141
|
-
|
|
1142
|
-
flash_id = rom_string + flash_id
|
|
1143
|
-
|
|
1144
|
-
return (flash_id, cfi_info, cfi)
|
|
1145
|
-
|
|
1146
|
-
def CheckROMStable(self):
|
|
1147
|
-
if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
|
|
1148
|
-
self.ReadROM(0, 64)
|
|
1149
|
-
buffer = self.ReadROM(0, 0x180)
|
|
1150
|
-
time.sleep(0.1)
|
|
1151
|
-
if buffer != self.ReadROM(0, 0x180):
|
|
1152
|
-
return False
|
|
1153
|
-
return True
|
|
1154
|
-
|
|
1155
|
-
def ReadInfo(self, setPinsAsInputs=False, checkRtc=False):
|
|
1156
|
-
if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
|
|
1157
|
-
data = {}
|
|
1158
|
-
if self.MODE == "DMG":
|
|
1159
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
1160
|
-
time.sleep(0.1)
|
|
1161
|
-
# Firmware check R26+
|
|
1162
|
-
if (int(self.FW[0]) >= 26):
|
|
1163
|
-
self.set_mode(self.DEVICE_CMD['RESET_MBC'])
|
|
1164
|
-
self.wait_for_ack()
|
|
1165
|
-
# Firmware check R26+
|
|
1166
|
-
|
|
1167
|
-
header = self.ReadROM(0, 0x180)
|
|
1168
|
-
if header is False or len(header) != 0x180: raise ConnectionError("Couldn’t read the cartridge information. Please try again.")
|
|
1169
|
-
if Util.DEBUG:
|
|
1170
|
-
with open("debug_header.bin", "wb") as f: f.write(header)
|
|
1171
|
-
|
|
1172
|
-
# Check for DACS
|
|
1173
|
-
dacs_8m = False
|
|
1174
|
-
if header[0x04:0x04+0x9C] == bytearray([0x00] * 0x9C):
|
|
1175
|
-
self.ReadROM(0x1FFFFE0, 20) # Unlock DACS
|
|
1176
|
-
header = self.ReadROM(0, 0x180)
|
|
1177
|
-
temp = self.ReadROM(0x1FFE000, 0x0C)
|
|
1178
|
-
if temp == b"AGBFLASHDACS":
|
|
1179
|
-
dacs_8m = True
|
|
1180
|
-
|
|
1181
|
-
# Parse ROM header
|
|
1182
|
-
if self.MODE == "DMG":
|
|
1183
|
-
data = RomFileDMG(header).GetHeader()
|
|
1184
|
-
|
|
1185
|
-
elif self.MODE == "AGB":
|
|
1186
|
-
data = RomFileAGB(header).GetHeader()
|
|
1187
|
-
# Check where the ROM data repeats (for unlicensed carts)
|
|
1188
|
-
size_check = header[0xA0:0xA0+16]
|
|
1189
|
-
currAddr = 0x10000
|
|
1190
|
-
while currAddr < 0x2000000:
|
|
1191
|
-
buffer = self.ReadROM(currAddr + 0xA0, 64)[:16]
|
|
1192
|
-
if buffer == size_check: break
|
|
1193
|
-
currAddr *= 2
|
|
1194
|
-
data["rom_size"] = currAddr
|
|
1195
|
-
if (data["3d_memory"] == True):
|
|
1196
|
-
data["rom_size"] = 0x4000000
|
|
1197
|
-
elif dacs_8m:
|
|
1198
|
-
data["dacs_8m"] = True
|
|
1199
|
-
|
|
1200
|
-
data["raw"] = header
|
|
1201
|
-
self.INFO = data
|
|
1202
|
-
self.INFO["flash_type"] = 0
|
|
1203
|
-
self.INFO["last_action"] = 0
|
|
1204
|
-
self.INFO["has_rtc"] = False
|
|
1205
|
-
self.INFO["no_rtc_reason"] = -1
|
|
1206
|
-
self.INFO["rtc_string"] = "(Unsupported in Legacy Mode)"
|
|
1207
|
-
self.INFO["dump_info"] = {}
|
|
1208
|
-
self.INFO["dump_info"]["header"] = data
|
|
1209
|
-
|
|
1210
|
-
if self.MODE == "DMG" and setPinsAsInputs: self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
|
|
1211
|
-
return data
|
|
1212
|
-
|
|
1213
|
-
def GetDumpReport(self):
|
|
1214
|
-
return Util.GetDumpReport(self.INFO["dump_info"], self)
|
|
1215
|
-
|
|
1216
|
-
def GetReadErrors(self):
|
|
1217
|
-
return self.READ_ERRORS
|
|
1218
|
-
|
|
1219
|
-
#################################################################
|
|
1220
|
-
|
|
1221
|
-
def BackupROM(self, fncSetProgress=None, args=None):
|
|
1222
|
-
from . import DataTransfer
|
|
1223
|
-
args['mode'] = 1
|
|
1224
|
-
args['port'] = self
|
|
1225
|
-
if self.WORKER is None:
|
|
1226
|
-
self.WORKER = DataTransfer.DataTransfer(args)
|
|
1227
|
-
self.WORKER.updateProgress.connect(fncSetProgress)
|
|
1228
|
-
else:
|
|
1229
|
-
self.WORKER.setConfig(args)
|
|
1230
|
-
self.WORKER.start()
|
|
1231
|
-
|
|
1232
|
-
def BackupRAM(self, fncSetProgress=None, args=None):
|
|
1233
|
-
from . import DataTransfer
|
|
1234
|
-
args['mode'] = 2
|
|
1235
|
-
args['port'] = self
|
|
1236
|
-
if fncSetProgress is False:
|
|
1237
|
-
self.TransferData(args=args, signal=None)
|
|
1238
|
-
else:
|
|
1239
|
-
if self.WORKER is None:
|
|
1240
|
-
self.WORKER = DataTransfer.DataTransfer(args)
|
|
1241
|
-
self.WORKER.updateProgress.connect(fncSetProgress)
|
|
1242
|
-
else:
|
|
1243
|
-
self.WORKER.setConfig(args)
|
|
1244
|
-
self.WORKER.start()
|
|
1245
|
-
|
|
1246
|
-
def RestoreRAM(self, fncSetProgress=None, args=None):
|
|
1247
|
-
from . import DataTransfer
|
|
1248
|
-
args['mode'] = 3
|
|
1249
|
-
args['port'] = self
|
|
1250
|
-
if self.WORKER is None:
|
|
1251
|
-
self.WORKER = DataTransfer.DataTransfer(args)
|
|
1252
|
-
self.WORKER.updateProgress.connect(fncSetProgress)
|
|
1253
|
-
else:
|
|
1254
|
-
self.WORKER.setConfig(args)
|
|
1255
|
-
self.WORKER.start()
|
|
1256
|
-
|
|
1257
|
-
def FlashROM(self, fncSetProgress=None, args=None):
|
|
1258
|
-
from . import DataTransfer
|
|
1259
|
-
args['mode'] = 4
|
|
1260
|
-
args['port'] = self
|
|
1261
|
-
if self.WORKER is None:
|
|
1262
|
-
self.WORKER = DataTransfer.DataTransfer(args)
|
|
1263
|
-
self.WORKER.updateProgress.connect(fncSetProgress)
|
|
1264
|
-
else:
|
|
1265
|
-
self.WORKER.setConfig(args)
|
|
1266
|
-
self.WORKER.start()
|
|
1267
|
-
|
|
1268
|
-
def TransferData(self, args, signal):
|
|
1269
|
-
if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
|
|
1270
|
-
self.SIGNAL = signal
|
|
1271
|
-
mode = args["mode"]
|
|
1272
|
-
path = args["path"]
|
|
1273
|
-
if "rtc" not in args: args["rtc"] = False
|
|
1274
|
-
self.INFO["last_path"] = path
|
|
1275
|
-
bank_size = 0x4000
|
|
1276
|
-
agb_3dmemory = False
|
|
1277
|
-
self.CANCEL_ARGS = {}
|
|
1278
|
-
self.POS = 0
|
|
1279
|
-
if self.INFO == None: self.ReadInfo()
|
|
1280
|
-
|
|
1281
|
-
# Firmware check R26+
|
|
1282
|
-
if (int(self.FW[0]) < 26) and self.MODE == "DMG" and "mbc" in args and args["mbc"] in (0x0B, 0x0D, 0xFD):
|
|
1283
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R26 or higher.", "abortable":False})
|
|
1284
|
-
return False
|
|
1285
|
-
# Firmware check R26+
|
|
1286
|
-
# Firmware check CFW
|
|
1287
|
-
if ("agb_rom_size" in args and args["agb_rom_size"] > 32 * 1024 * 1024) or (self.MODE == "DMG" and "mbc" in args and not self.IsSupportedMbc(args["mbc"])) or (self.MODE == "AGB" and "dacs_8m" in self.INFO and self.INFO["dacs_8m"] is True): # 3D Memory
|
|
1288
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please try the dedicated insideGadgets software programs, try updating the firmware or upgrade to a new hardware revision.".format(APPNAME, self.GetFullName()), "abortable":False})
|
|
1289
|
-
return False
|
|
1290
|
-
# Firmware check CFW
|
|
1291
|
-
|
|
1292
|
-
# Enable TAMA5
|
|
1293
|
-
if self.MODE == "DMG" and "mbc" in args and args["mbc"] == 0xFD:
|
|
1294
|
-
self.ReadInfo()
|
|
1295
|
-
tama5_check = int.from_bytes(self.ReadROM(0xA000, 64)[:1], byteorder="little")
|
|
1296
|
-
dprint("Enabling TAMA5")
|
|
1297
|
-
lives = 20
|
|
1298
|
-
while (tama5_check & 3) != 1:
|
|
1299
|
-
dprint("└Current value is 0x{:X}, now writing 0xA001=0x{:X}".format(tama5_check, 0x0A))
|
|
1300
|
-
self.cart_write(0xA001, 0x0A, cs=True)
|
|
1301
|
-
tama5_check = int.from_bytes(self.ReadROM(0xA000, 64)[:1], byteorder="little")
|
|
1302
|
-
time.sleep(0.1)
|
|
1303
|
-
lives -= 1
|
|
1304
|
-
if lives < 0:
|
|
1305
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The TAMA5 cartridge doesn’t seem to respond. Please try again.", "abortable":False})
|
|
1306
|
-
return False
|
|
1307
|
-
|
|
1308
|
-
# main work starts here
|
|
1309
|
-
self.INFO["last_action"] = mode
|
|
1310
|
-
self.FAST_READ = False
|
|
1311
|
-
if mode == 1: # Backup ROM
|
|
1312
|
-
self.INFO["dump_info"]["timestamp"] = datetime.datetime.now().astimezone().replace(microsecond=0).isoformat()
|
|
1313
|
-
self.INFO["dump_info"]["file_name"] = args["path"]
|
|
1314
|
-
self.INFO["dump_info"]["file_size"] = args["rom_size"]
|
|
1315
|
-
self.INFO["dump_info"]["cart_type"] = args["cart_type"]
|
|
1316
|
-
self.INFO["dump_info"]["system"] = self.MODE
|
|
1317
|
-
self.INFO["dump_info"]["transfer_size"] = 64
|
|
1318
|
-
fast_read_mode = False #args["fast_read_mode"]
|
|
1319
|
-
buffer_len = 0x1000
|
|
1320
|
-
if self.MODE == "DMG":
|
|
1321
|
-
self.INFO["dump_info"]["rom_size"] = args["rom_size"]
|
|
1322
|
-
self.INFO["dump_info"]["mapper_type"] = args["mbc"]
|
|
1323
|
-
supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
|
|
1324
|
-
mbc = args["mbc"]
|
|
1325
|
-
bank_count = int(args["rom_size"] / 0x4000)
|
|
1326
|
-
|
|
1327
|
-
if mbc == 0x104: # M161
|
|
1328
|
-
bank_count = 8
|
|
1329
|
-
bank_size = 0x8000
|
|
1330
|
-
|
|
1331
|
-
if fast_read_mode:
|
|
1332
|
-
buffer_len = 0x4000
|
|
1333
|
-
self.FAST_READ = True
|
|
1334
|
-
rom_size = bank_count * bank_size
|
|
1335
|
-
|
|
1336
|
-
elif self.MODE == "AGB":
|
|
1337
|
-
self.INFO["dump_info"]["mapper_type"] = None
|
|
1338
|
-
supported_carts = list(self.SUPPORTED_CARTS['AGB'].values())
|
|
1339
|
-
rom_size = args["agb_rom_size"]
|
|
1340
|
-
self.INFO["dump_info"]["rom_size"] = rom_size
|
|
1341
|
-
bank_count = 1
|
|
1342
|
-
endAddr = rom_size
|
|
1343
|
-
if rom_size == 64 * 1024 * 1024: # 3D Memory
|
|
1344
|
-
agb_3dmemory = True
|
|
1345
|
-
if fast_read_mode:
|
|
1346
|
-
buffer_len = 0x1000
|
|
1347
|
-
self.FAST_READ = True
|
|
1348
|
-
else:
|
|
1349
|
-
buffer_len = 0x200
|
|
1350
|
-
|
|
1351
|
-
elif fast_read_mode:
|
|
1352
|
-
buffer_len = 0x10000
|
|
1353
|
-
self.FAST_READ = True
|
|
1354
|
-
|
|
1355
|
-
if rom_size == 0:
|
|
1356
|
-
rom_size = 32 * 1024 * 1024
|
|
1357
|
-
|
|
1358
|
-
# Read a bit before actually dumping (fixes some carts that don’t like SET_PINS_AS_INPUTS)
|
|
1359
|
-
self.ReadROM(0, 64)
|
|
1360
|
-
|
|
1361
|
-
# Cart type check (GB Memory)
|
|
1362
|
-
flashcart_meta = False
|
|
1363
|
-
if not isinstance(args["cart_type"], dict):
|
|
1364
|
-
for i in range(0, len(supported_carts)):
|
|
1365
|
-
if i == args["cart_type"]: flashcart_meta = supported_carts[i]
|
|
1366
|
-
if flashcart_meta == "RETAIL": flashcart_meta = False
|
|
1367
|
-
else:
|
|
1368
|
-
flashcart_meta = args["cart_type"]
|
|
1369
|
-
|
|
1370
|
-
if flashcart_meta is not False and "unlock_before_rom_dump" in flashcart_meta and flashcart_meta["unlock_before_rom_dump"] is True:
|
|
1371
|
-
# Unlock Flash
|
|
1372
|
-
if "unlock" in flashcart_meta["commands"]:
|
|
1373
|
-
for i in range(0, len(flashcart_meta["commands"]["unlock"])):
|
|
1374
|
-
addr = flashcart_meta["commands"]["unlock"][i][0]
|
|
1375
|
-
data = flashcart_meta["commands"]["unlock"][i][1]
|
|
1376
|
-
count = flashcart_meta["commands"]["unlock"][i][2]
|
|
1377
|
-
for _ in range(0, count):
|
|
1378
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
1379
|
-
|
|
1380
|
-
# Reset Flash
|
|
1381
|
-
if "reset" in flashcart_meta["commands"]:
|
|
1382
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
1383
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
1384
|
-
|
|
1385
|
-
data_dump = bytearray()
|
|
1386
|
-
|
|
1387
|
-
startAddr = 0
|
|
1388
|
-
currAddr = 0
|
|
1389
|
-
recvBytes = 0
|
|
1390
|
-
|
|
1391
|
-
try:
|
|
1392
|
-
file = open(path, "wb")
|
|
1393
|
-
except PermissionError:
|
|
1394
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"FlashGBX doesn’t have permission to access this file for writing:\n" + path, "abortable":False})
|
|
1395
|
-
return False
|
|
1396
|
-
|
|
1397
|
-
if self.MODE == "DMG":
|
|
1398
|
-
endAddr = bank_size
|
|
1399
|
-
|
|
1400
|
-
dprint("bank_count: {:d}".format(bank_count))
|
|
1401
|
-
|
|
1402
|
-
self.SetProgress({"action":"INITIALIZE", "method":"ROM_READ", "size":rom_size})
|
|
1403
|
-
|
|
1404
|
-
for bank in range(0, bank_count):
|
|
1405
|
-
if self.MODE == "DMG":
|
|
1406
|
-
if bank > 0:
|
|
1407
|
-
startAddr = bank_size
|
|
1408
|
-
endAddr = startAddr + bank_size
|
|
1409
|
-
|
|
1410
|
-
if mbc in (0x0B, 0x0D) and bank % 0x20 == 0: # MMM01
|
|
1411
|
-
startAddr = 0
|
|
1412
|
-
endAddr = bank_size
|
|
1413
|
-
elif mbc == 0x104: # M161
|
|
1414
|
-
startAddr = 0
|
|
1415
|
-
endAddr = 0x8000
|
|
1416
|
-
elif mbc in (0x01, 0x02, 0x03): # MBC1
|
|
1417
|
-
if bank & 0x1F:
|
|
1418
|
-
startAddr = 0x4000
|
|
1419
|
-
endAddr = 0x8000
|
|
1420
|
-
else:
|
|
1421
|
-
startAddr = 0
|
|
1422
|
-
endAddr = 0x4000
|
|
1423
|
-
|
|
1424
|
-
self.SetBankROM(bank, mbc)
|
|
1425
|
-
|
|
1426
|
-
for currAddr in range(startAddr, endAddr, buffer_len):
|
|
1427
|
-
if self.CANCEL:
|
|
1428
|
-
cancel_args = {"action":"ABORT", "abortable":False}
|
|
1429
|
-
cancel_args.update(self.CANCEL_ARGS)
|
|
1430
|
-
self.CANCEL_ARGS = {}
|
|
1431
|
-
self.SetProgress(cancel_args)
|
|
1432
|
-
try:
|
|
1433
|
-
file.close()
|
|
1434
|
-
except:
|
|
1435
|
-
pass
|
|
1436
|
-
return
|
|
1437
|
-
|
|
1438
|
-
if currAddr == startAddr:
|
|
1439
|
-
buffer = self.ReadROM(currAddr, buffer_len, True, agb_3dmemory=agb_3dmemory)
|
|
1440
|
-
else:
|
|
1441
|
-
buffer = self.ReadROM(currAddr, buffer_len, False, agb_3dmemory=agb_3dmemory)
|
|
1442
|
-
|
|
1443
|
-
if buffer == False:
|
|
1444
|
-
self.CANCEL = True
|
|
1445
|
-
self.ERROR = True
|
|
1446
|
-
continue
|
|
1447
|
-
|
|
1448
|
-
data_dump.extend(buffer)
|
|
1449
|
-
file.write(buffer)
|
|
1450
|
-
recvBytes += buffer_len
|
|
1451
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":recvBytes})
|
|
1452
|
-
|
|
1453
|
-
file.close()
|
|
1454
|
-
|
|
1455
|
-
# Read hidden sector (GB Memory)
|
|
1456
|
-
if flashcart_meta is not False and "read_hidden_sector" in flashcart_meta["commands"] and "hidden_sector_size" in flashcart_meta:
|
|
1457
|
-
# Unlock Flash
|
|
1458
|
-
if "unlock" in flashcart_meta["commands"]:
|
|
1459
|
-
for i in range(0, len(flashcart_meta["commands"]["unlock"])):
|
|
1460
|
-
addr = flashcart_meta["commands"]["unlock"][i][0]
|
|
1461
|
-
data = flashcart_meta["commands"]["unlock"][i][1]
|
|
1462
|
-
count = flashcart_meta["commands"]["unlock"][i][2]
|
|
1463
|
-
for _ in range(0, count):
|
|
1464
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
1465
|
-
|
|
1466
|
-
# Request hidden sector
|
|
1467
|
-
for i in range(0, len(flashcart_meta["commands"]["read_hidden_sector"])):
|
|
1468
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["read_hidden_sector"][i][0], flashcart_meta["commands"]["read_hidden_sector"][i][1])
|
|
1469
|
-
|
|
1470
|
-
# Read data
|
|
1471
|
-
buffer = self.ReadROM(0, flashcart_meta["hidden_sector_size"], True)
|
|
1472
|
-
path2 = os.path.splitext(path)[0] + ".map"
|
|
1473
|
-
try:
|
|
1474
|
-
file = open(path2, "wb")
|
|
1475
|
-
except PermissionError:
|
|
1476
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"FlashGBX doesn’t have permission to access this file for writing:\n" + path2, "abortable":False})
|
|
1477
|
-
return False
|
|
1478
|
-
file.write(buffer)
|
|
1479
|
-
file.close()
|
|
1480
|
-
|
|
1481
|
-
# Calculate Global Checksum
|
|
1482
|
-
buffer = data_dump
|
|
1483
|
-
self.INFO["file_crc32"] = zlib.crc32(buffer) & 0xFFFFFFFF
|
|
1484
|
-
self.INFO["file_sha1"] = hashlib.sha1(buffer).hexdigest()
|
|
1485
|
-
self.INFO["file_sha256"] = hashlib.sha256(buffer).hexdigest()
|
|
1486
|
-
self.INFO["file_md5"] = hashlib.md5(buffer).hexdigest()
|
|
1487
|
-
self.INFO["dump_info"]["hash_crc32"] = self.INFO["file_crc32"]
|
|
1488
|
-
self.INFO["dump_info"]["hash_sha1"] = self.INFO["file_sha1"]
|
|
1489
|
-
self.INFO["dump_info"]["hash_sha256"] = self.INFO["file_sha256"]
|
|
1490
|
-
self.INFO["dump_info"]["hash_md5"] = self.INFO["file_md5"]
|
|
1491
|
-
chk = 0
|
|
1492
|
-
if self.MODE == "DMG":
|
|
1493
|
-
self.INFO["dump_info"]["header"] = RomFileDMG(buffer[:0x180]).GetHeader(unchanged=True)
|
|
1494
|
-
if mbc in (0x0B, 0x0D): # MMM01
|
|
1495
|
-
self.set_mode(self.DEVICE_CMD['RESET_MBC'])
|
|
1496
|
-
self.wait_for_ack()
|
|
1497
|
-
temp_data = data_dump[0:-0x8000]
|
|
1498
|
-
temp_menu = data_dump[-0x8000:]
|
|
1499
|
-
temp_dump = temp_menu + temp_data
|
|
1500
|
-
for i in range(0, len(temp_dump), 2):
|
|
1501
|
-
if i != 0x14E:
|
|
1502
|
-
chk = chk + temp_dump[i + 1]
|
|
1503
|
-
chk = chk + temp_dump[i]
|
|
1504
|
-
chk = chk & 0xFFFF
|
|
1505
|
-
|
|
1506
|
-
else:
|
|
1507
|
-
for i in range(0, len(data_dump), 2):
|
|
1508
|
-
if i != 0x14E:
|
|
1509
|
-
chk = chk + data_dump[i + 1]
|
|
1510
|
-
chk = chk + data_dump[i]
|
|
1511
|
-
chk = chk & 0xFFFF
|
|
1512
|
-
|
|
1513
|
-
elif self.MODE == "AGB":
|
|
1514
|
-
self.INFO["dump_info"]["header"] = RomFileAGB(buffer[:0x180]).GetHeader(unchanged=True)
|
|
1515
|
-
chk = self.INFO["file_crc32"]
|
|
1516
|
-
|
|
1517
|
-
temp_ver = "N/A"
|
|
1518
|
-
ids = [ b"SRAM_", b"EEPROM_V", b"FLASH_V", b"FLASH512_V", b"FLASH1M_V", b"AGB_8MDACS_DL_V" ]
|
|
1519
|
-
for id in ids:
|
|
1520
|
-
temp_pos = buffer.find(id)
|
|
1521
|
-
if temp_pos > 0:
|
|
1522
|
-
temp_ver = buffer[temp_pos:temp_pos+0x20]
|
|
1523
|
-
temp_ver = temp_ver[:temp_ver.index(0x00)].decode("ascii", "replace")
|
|
1524
|
-
break
|
|
1525
|
-
self.INFO["dump_info"]["agb_savelib"] = temp_ver
|
|
1526
|
-
self.INFO["dump_info"]["agb_save_flash_id"] = None
|
|
1527
|
-
|
|
1528
|
-
self.INFO["rom_checksum_calc"] = chk
|
|
1529
|
-
|
|
1530
|
-
# Check for ROM loops
|
|
1531
|
-
self.INFO["loop_detected"] = False
|
|
1532
|
-
temp = min(0x2000000, len(data_dump))
|
|
1533
|
-
while temp > 0x4000:
|
|
1534
|
-
temp = temp >> 1
|
|
1535
|
-
if (data_dump[0:0x4000] == data_dump[temp:temp+0x4000]):
|
|
1536
|
-
if data_dump[0:temp] == data_dump[temp:temp*2]:
|
|
1537
|
-
self.INFO["loop_detected"] = temp
|
|
1538
|
-
else:
|
|
1539
|
-
break
|
|
1540
|
-
|
|
1541
|
-
self.SetProgress({"action":"FINISHED"})
|
|
1542
|
-
|
|
1543
|
-
#########################################
|
|
1544
|
-
|
|
1545
|
-
elif mode == 2 or mode == 3: # Backup or Restore RAM
|
|
1546
|
-
data_dump = bytearray()
|
|
1547
|
-
data_import = bytearray()
|
|
1548
|
-
self.ReadROM(0, 64) # fix
|
|
1549
|
-
audio_low = False
|
|
1550
|
-
|
|
1551
|
-
startAddr = 0
|
|
1552
|
-
if self.MODE == "DMG":
|
|
1553
|
-
bank_size = 0x2000
|
|
1554
|
-
mbc = args["mbc"]
|
|
1555
|
-
#save_size = args["save_type"]
|
|
1556
|
-
save_size = Util.DMG_Header_RAM_Sizes_Flasher_Map[Util.DMG_Header_RAM_Sizes_Map.index(args["save_type"])]
|
|
1557
|
-
bank_count = int(max(save_size, bank_size) / bank_size)
|
|
1558
|
-
self.EnableRAM(mbc=mbc, enable=True)
|
|
1559
|
-
startAddr = 0xA000
|
|
1560
|
-
if mode == 2: # Backup
|
|
1561
|
-
transfer_size = 512
|
|
1562
|
-
else: # Restore
|
|
1563
|
-
transfer_size = 64
|
|
1564
|
-
|
|
1565
|
-
if mbc == 0xFD: # TAMA5
|
|
1566
|
-
if args["rtc"]: save_size += 0x10
|
|
1567
|
-
elif mbc == 0x22: # MBC7 EEPROM
|
|
1568
|
-
transfer_size = 32
|
|
1569
|
-
self.cart_write(0x4000, 0x40)
|
|
1570
|
-
if mode == 3: # Restore
|
|
1571
|
-
self.cart_write(0xA080, 0x00) # init eeprom
|
|
1572
|
-
self.cart_write(0xA080, 0x80)
|
|
1573
|
-
|
|
1574
|
-
self.cart_write(0xA080, 0x80) # init command
|
|
1575
|
-
self.cart_write(0xA080, 0xC0)
|
|
1576
|
-
self.cart_write(0xA080, 0x82)
|
|
1577
|
-
self.cart_write(0xA080, 0xC2)
|
|
1578
|
-
|
|
1579
|
-
self.cart_write(0xA080, 0x80) # write enable command
|
|
1580
|
-
self.cart_write(0xA080, 0xC0)
|
|
1581
|
-
self.cart_write(0xA080, 0x80)
|
|
1582
|
-
self.cart_write(0xA080, 0xC0)
|
|
1583
|
-
self.cart_write(0xA080, 0x82)
|
|
1584
|
-
self.cart_write(0xA080, 0xC2)
|
|
1585
|
-
self.cart_write(0xA080, 0x82)
|
|
1586
|
-
self.cart_write(0xA080, 0xC2)
|
|
1587
|
-
for _ in range(0, 6):
|
|
1588
|
-
self.cart_write(0xA080, 0x80)
|
|
1589
|
-
self.cart_write(0xA080, 0xC0)
|
|
1590
|
-
|
|
1591
|
-
if transfer_size >= save_size:
|
|
1592
|
-
transfer_size = save_size
|
|
1593
|
-
bank_size = save_size
|
|
1594
|
-
|
|
1595
|
-
# Check for DMG-MBC5-32M-FLASH
|
|
1596
|
-
self.cart_write(0x2000, 0x00)
|
|
1597
|
-
self.cart_write(0x4000, 0x90)
|
|
1598
|
-
flash_id = self.ReadROM(0x4000, 2)
|
|
1599
|
-
if flash_id == bytearray([0xB0, 0x88]): audio_low = True
|
|
1600
|
-
self.cart_write(0x4000, 0xF0)
|
|
1601
|
-
self.cart_write(0x4000, 0xFF)
|
|
1602
|
-
self.cart_write(0x2000, 0x01)
|
|
1603
|
-
if audio_low:
|
|
1604
|
-
dprint("DMG-MBC5-32M-FLASH Development Cartridge detected")
|
|
1605
|
-
self.set_mode(self.DEVICE_CMD["AUDIO_LOW"])
|
|
1606
|
-
self.cart_write(0x4000, 0x00)
|
|
1607
|
-
|
|
1608
|
-
elif self.MODE == "AGB":
|
|
1609
|
-
bank_size = 0x10000
|
|
1610
|
-
save_type = args["save_type"]
|
|
1611
|
-
bank_count = 1
|
|
1612
|
-
eeprom_size = 0
|
|
1613
|
-
transfer_size = 64
|
|
1614
|
-
|
|
1615
|
-
if save_type == 0:
|
|
1616
|
-
return
|
|
1617
|
-
elif save_type == 1: # EEPROM 512 Byte
|
|
1618
|
-
save_size = 512
|
|
1619
|
-
read_command = 'GBA_READ_EEPROM'
|
|
1620
|
-
write_command = 'GBA_WRITE_EEPROM'
|
|
1621
|
-
transfer_size = 8
|
|
1622
|
-
eeprom_size = 1
|
|
1623
|
-
elif save_type == 2: # EEPROM 8 KB
|
|
1624
|
-
save_size = 8 * 1024
|
|
1625
|
-
read_command = 'GBA_READ_EEPROM'
|
|
1626
|
-
write_command = 'GBA_WRITE_EEPROM'
|
|
1627
|
-
transfer_size = 8
|
|
1628
|
-
eeprom_size = 2
|
|
1629
|
-
elif save_type == 3: # SRAM 32 KB
|
|
1630
|
-
save_size = 32 * 1024
|
|
1631
|
-
read_command = 'GBA_READ_SRAM'
|
|
1632
|
-
write_command = 'GBA_WRITE_SRAM'
|
|
1633
|
-
elif save_type == 7: # SRAM 64 KB
|
|
1634
|
-
save_size = 64 * 1024
|
|
1635
|
-
read_command = 'GBA_READ_SRAM'
|
|
1636
|
-
write_command = 'GBA_WRITE_SRAM'
|
|
1637
|
-
elif save_type == 8: # SRAM 128 KB
|
|
1638
|
-
save_size = 128 * 1024
|
|
1639
|
-
read_command = 'GBA_READ_SRAM'
|
|
1640
|
-
write_command = 'GBA_WRITE_SRAM'
|
|
1641
|
-
bank_count = 2
|
|
1642
|
-
elif save_type == 4: # FLASH 64 KB
|
|
1643
|
-
save_size = 64 * 1024
|
|
1644
|
-
read_command = 'GBA_READ_SRAM'
|
|
1645
|
-
elif save_type == 5: # FLASH 128 KB
|
|
1646
|
-
save_size = 128 * 1024
|
|
1647
|
-
read_command = 'GBA_READ_SRAM'
|
|
1648
|
-
bank_count = 2
|
|
1649
|
-
else:
|
|
1650
|
-
return
|
|
1651
|
-
|
|
1652
|
-
# Get Save Flash Manufacturer
|
|
1653
|
-
maker_id = None
|
|
1654
|
-
if save_type == 4 or save_type == 5:
|
|
1655
|
-
maker_id = self.ReadFlashSaveMakerID()
|
|
1656
|
-
if maker_id == "ATMEL" and mode == 3:
|
|
1657
|
-
transfer_size = 128
|
|
1658
|
-
elif maker_id == "SANYO":
|
|
1659
|
-
if int(self.FW[0]) < 24:
|
|
1660
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R24 or higher.", "abortable":False})
|
|
1661
|
-
return False
|
|
1662
|
-
|
|
1663
|
-
# Prepare some stuff
|
|
1664
|
-
if mode == 2: # Backup
|
|
1665
|
-
self.SetProgress({"action":"INITIALIZE", "method":"SAVE_READ", "size":save_size})
|
|
1666
|
-
|
|
1667
|
-
elif mode == 3: # Restore
|
|
1668
|
-
if args["erase"]: # Erase
|
|
1669
|
-
if args["mbc"] == 0xFD: # TAMA5
|
|
1670
|
-
data_import = save_size * b'\x00'
|
|
1671
|
-
else:
|
|
1672
|
-
data_import = save_size * b'\xFF'
|
|
1673
|
-
self.INFO["save_erase"] = True
|
|
1674
|
-
else:
|
|
1675
|
-
with open(path, "rb") as file: data_import = file.read()
|
|
1676
|
-
|
|
1677
|
-
while len(data_import) < save_size:
|
|
1678
|
-
data_import += bytearray(data_import)
|
|
1679
|
-
data_import = data_import[:save_size]
|
|
1680
|
-
|
|
1681
|
-
self.SetProgress({"action":"INITIALIZE", "method":"SAVE_WRITE", "size":save_size})
|
|
1682
|
-
|
|
1683
|
-
currAddr = 0
|
|
1684
|
-
pos = 0
|
|
1685
|
-
|
|
1686
|
-
for bank in range(0, bank_count):
|
|
1687
|
-
if self.MODE == "DMG":
|
|
1688
|
-
endAddr = startAddr + bank_size
|
|
1689
|
-
if endAddr > (startAddr + save_size): endAddr = startAddr + save_size
|
|
1690
|
-
if mbc != 0x22: # exclude MBC7
|
|
1691
|
-
self.SetBankRAM(bank, mbc)
|
|
1692
|
-
|
|
1693
|
-
elif self.MODE == "AGB":
|
|
1694
|
-
endAddr = startAddr + min(save_size, bank_size)
|
|
1695
|
-
if endAddr > (startAddr + save_size): endAddr = startAddr + save_size
|
|
1696
|
-
if save_type == 1 or save_type == 2: # EEPROM
|
|
1697
|
-
self.set_number(eeprom_size, self.DEVICE_CMD["GBA_SET_EEPROM_SIZE"])
|
|
1698
|
-
elif save_type == 8: # 1M SRAM
|
|
1699
|
-
self.gbx_flash_write_address_byte(0x1000000, bank)
|
|
1700
|
-
elif (save_type == 4 or save_type == 5) and bank > 0: # FLASH
|
|
1701
|
-
self.set_number(bank, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
|
|
1702
|
-
|
|
1703
|
-
self.set_number(startAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
1704
|
-
|
|
1705
|
-
buffer_len = transfer_size
|
|
1706
|
-
sector = 0
|
|
1707
|
-
for currAddr in range(startAddr, endAddr, buffer_len):
|
|
1708
|
-
if self.CANCEL:
|
|
1709
|
-
if self.MODE == "DMG":
|
|
1710
|
-
self.EnableRAM(mbc=mbc, enable=False)
|
|
1711
|
-
elif self.MODE == "AGB":
|
|
1712
|
-
if bank > 0: self.set_number(0, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
|
|
1713
|
-
self.ReadInfo()
|
|
1714
|
-
cancel_args = {"action":"ABORT", "abortable":False}
|
|
1715
|
-
cancel_args.update(self.CANCEL_ARGS)
|
|
1716
|
-
self.CANCEL_ARGS = {}
|
|
1717
|
-
self.SetProgress(cancel_args)
|
|
1718
|
-
return
|
|
1719
|
-
|
|
1720
|
-
if mode == 2: # Backup
|
|
1721
|
-
if self.MODE == "DMG":
|
|
1722
|
-
if mbc == 0xFD: # TAMA5
|
|
1723
|
-
buffer = self.ReadRAM_TAMA5(rtc=args["rtc"])
|
|
1724
|
-
elif mbc == 0x22: # MBC7 EEPROM
|
|
1725
|
-
self.set_mode(self.DEVICE_CMD["READ_EEPROM_MBC7"])
|
|
1726
|
-
buffer = self.read(length=buffer_len, last=True, ask_next_bytes=False)
|
|
1727
|
-
if buffer == False:
|
|
1728
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Backup failed, please try again.", "abortable":False})
|
|
1729
|
-
return False
|
|
1730
|
-
else:
|
|
1731
|
-
buffer = self.ReadROM(currAddr, buffer_len)
|
|
1732
|
-
elif self.MODE == "AGB":
|
|
1733
|
-
self.set_mode(self.DEVICE_CMD[read_command])
|
|
1734
|
-
buffer = self.read(length=buffer_len, last=True, ask_next_bytes=False)
|
|
1735
|
-
if buffer == False:
|
|
1736
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Backup failed, please try again.", "abortable":False})
|
|
1737
|
-
return False
|
|
1738
|
-
|
|
1739
|
-
data_dump.extend(buffer)
|
|
1740
|
-
#file.write(buffer)
|
|
1741
|
-
|
|
1742
|
-
elif mode == 3: # Restore
|
|
1743
|
-
data = data_import[pos:pos+buffer_len]
|
|
1744
|
-
if self.MODE == "DMG":
|
|
1745
|
-
if mbc == 0xFD: # TAMA5
|
|
1746
|
-
self.WriteRAM_TAMA5(data, rtc=args["rtc"])
|
|
1747
|
-
elif mbc == 0x22: # MBC7 EEPROM
|
|
1748
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["WRITE_EEPROM_MBC7"], data)
|
|
1749
|
-
self.wait_for_ack()
|
|
1750
|
-
else:
|
|
1751
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["WRITE_RAM"], data)
|
|
1752
|
-
self.wait_for_ack()
|
|
1753
|
-
|
|
1754
|
-
elif self.MODE == "AGB":
|
|
1755
|
-
if save_type == 4 or save_type == 5: # FLASH
|
|
1756
|
-
if maker_id == "ATMEL":
|
|
1757
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_ATMEL"], data)
|
|
1758
|
-
self.wait_for_ack()
|
|
1759
|
-
else:
|
|
1760
|
-
if (currAddr % 4096 == 0):
|
|
1761
|
-
self.set_number(sector, self.DEVICE_CMD["GBA_FLASH_4K_SECTOR_ERASE"])
|
|
1762
|
-
self.wait_for_ack()
|
|
1763
|
-
sector += 1
|
|
1764
|
-
lives = 50
|
|
1765
|
-
while True: # wait for 0xFF (= erase done)
|
|
1766
|
-
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
1767
|
-
self.set_mode(self.DEVICE_CMD[read_command])
|
|
1768
|
-
buffer = self.read(buffer_len, last=True)
|
|
1769
|
-
if buffer[0] == 0xFF: break
|
|
1770
|
-
time.sleep(0.01)
|
|
1771
|
-
lives -= 1
|
|
1772
|
-
if lives == 0:
|
|
1773
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Accessing the save data flash chip failed. Please make sure you selected the correct save type. If you are using a reproduction cartridge, check if it really is equipped with a flash chip for save data, or if it uses SRAM for save data instead.", "abortable":False})
|
|
1774
|
-
return False
|
|
1775
|
-
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
1776
|
-
|
|
1777
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BYTE"], data)
|
|
1778
|
-
self.wait_for_ack()
|
|
1779
|
-
|
|
1780
|
-
else: # EEPROM / SRAM
|
|
1781
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD[write_command], data)
|
|
1782
|
-
self.wait_for_ack()
|
|
1783
|
-
|
|
1784
|
-
self.SetProgress({"action":"WRITE", "bytes_added":len(data)})
|
|
1785
|
-
|
|
1786
|
-
pos += buffer_len
|
|
1787
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":pos})
|
|
1788
|
-
|
|
1789
|
-
self.INFO["transferred"] = pos
|
|
1790
|
-
|
|
1791
|
-
if self.MODE == "DMG":
|
|
1792
|
-
# MBC7 EEPROM write end
|
|
1793
|
-
if mode == 3 and mbc == 0x22:
|
|
1794
|
-
self.cart_write(0xA080, 0x00) # init eeprom
|
|
1795
|
-
self.cart_write(0xA080, 0x80)
|
|
1796
|
-
|
|
1797
|
-
self.cart_write(0xA080, 0x80) # init command
|
|
1798
|
-
self.cart_write(0xA080, 0xC0)
|
|
1799
|
-
self.cart_write(0xA080, 0x82)
|
|
1800
|
-
self.cart_write(0xA080, 0xC2)
|
|
1801
|
-
|
|
1802
|
-
self.cart_write(0xA080, 0x80) # disable write command
|
|
1803
|
-
self.cart_write(0xA080, 0xC0)
|
|
1804
|
-
self.cart_write(0xA080, 0x80)
|
|
1805
|
-
self.cart_write(0xA080, 0xC0)
|
|
1806
|
-
self.cart_write(0xA080, 0x80)
|
|
1807
|
-
self.cart_write(0xA080, 0xC0)
|
|
1808
|
-
self.cart_write(0xA080, 0x80)
|
|
1809
|
-
self.cart_write(0xA080, 0xC0)
|
|
1810
|
-
for _ in range(0, 6):
|
|
1811
|
-
self.cart_write(0xA080, 0x80)
|
|
1812
|
-
self.cart_write(0xA080, 0xC0)
|
|
1813
|
-
|
|
1814
|
-
# RTC for MBC3+RTC+SRAM+BATTERY
|
|
1815
|
-
elif mbc in (0x10, 0x110) and args["rtc"]:
|
|
1816
|
-
buffer = bytearray()
|
|
1817
|
-
self.cart_write(0x6000, 0)
|
|
1818
|
-
self.cart_write(0x6000, 1)
|
|
1819
|
-
|
|
1820
|
-
if mode == 2: # Backup
|
|
1821
|
-
for i in range(0x8, 0xD):
|
|
1822
|
-
self.cart_write(0x4000, i)
|
|
1823
|
-
buffer.extend(struct.pack("<I", ord(self.ReadROM(0xA000, 1))))
|
|
1824
|
-
buffer.extend(buffer)
|
|
1825
|
-
ts = int(time.time())
|
|
1826
|
-
buffer.extend(struct.pack("<Q", ts))
|
|
1827
|
-
#file.write(buffer)
|
|
1828
|
-
|
|
1829
|
-
# RTC for HuC-3+RTC+SRAM+BATTERY
|
|
1830
|
-
elif mbc == 0xFE and args["rtc"]:
|
|
1831
|
-
buffer = bytearray()
|
|
1832
|
-
|
|
1833
|
-
self.cart_write(0x0000, 0x0B)
|
|
1834
|
-
self.cart_write(0xA000, 0x60)
|
|
1835
|
-
self.cart_write(0x0000, 0x0D)
|
|
1836
|
-
self.cart_write(0xA000, 0xFE)
|
|
1837
|
-
self.cart_write(0x0000, 0x0C)
|
|
1838
|
-
self.cart_write(0x0000, 0x00)
|
|
1839
|
-
|
|
1840
|
-
self.cart_write(0x0000, 0x0B)
|
|
1841
|
-
self.cart_write(0xA000, 0x40)
|
|
1842
|
-
self.cart_write(0x0000, 0x0D)
|
|
1843
|
-
self.cart_write(0xA000, 0xFE)
|
|
1844
|
-
self.cart_write(0x0000, 0x0C)
|
|
1845
|
-
self.cart_write(0x0000, 0x00)
|
|
1846
|
-
|
|
1847
|
-
if mode == 2: # Backup
|
|
1848
|
-
rtc = 0
|
|
1849
|
-
for i in range(0, 6):
|
|
1850
|
-
self.cart_write(0x0000, 0x0B)
|
|
1851
|
-
self.cart_write(0xA000, 0x10)
|
|
1852
|
-
self.cart_write(0x0000, 0x0D)
|
|
1853
|
-
self.cart_write(0xA000, 0xFE)
|
|
1854
|
-
self.cart_write(0x0000, 0x0C)
|
|
1855
|
-
rtc |= (self.ReadROM(0xA000, 64)[0] & 0xF) << (i * 4)
|
|
1856
|
-
self.cart_write(0x0000, 0x00)
|
|
1857
|
-
|
|
1858
|
-
buffer.extend(struct.pack("<L", rtc))
|
|
1859
|
-
ts = int(time.time())
|
|
1860
|
-
buffer.extend(struct.pack("<Q", ts))
|
|
1861
|
-
|
|
1862
|
-
elif mode == 3 and len(data_import) == save_size + 0x0C: # Restore
|
|
1863
|
-
buffer = data_import[-0x0C:-0x08]
|
|
1864
|
-
|
|
1865
|
-
for i in range(0, 3):
|
|
1866
|
-
self.cart_write(0x0000, 0x0B)
|
|
1867
|
-
self.cart_write(0xA000, 0x30 | (buffer[i] & 0xF))
|
|
1868
|
-
self.cart_write(0x0000, 0x0D)
|
|
1869
|
-
self.cart_write(0xA000, 0xFE)
|
|
1870
|
-
self.cart_write(0x0000, 0x00)
|
|
1871
|
-
self.cart_write(0x0000, 0x0D)
|
|
1872
|
-
|
|
1873
|
-
self.cart_write(0x0000, 0x0B)
|
|
1874
|
-
self.cart_write(0xA000, 0x30 | ((buffer[i] >> 4) & 0xF))
|
|
1875
|
-
self.cart_write(0x0000, 0x0D)
|
|
1876
|
-
self.cart_write(0xA000, 0xFE)
|
|
1877
|
-
self.cart_write(0x0000, 0x00)
|
|
1878
|
-
self.cart_write(0x0000, 0x0D)
|
|
1879
|
-
|
|
1880
|
-
self.cart_write(0x0000, 0x0B)
|
|
1881
|
-
self.cart_write(0xA000, 0x31)
|
|
1882
|
-
self.cart_write(0x0000, 0x0D)
|
|
1883
|
-
self.cart_write(0xA000, 0xFE)
|
|
1884
|
-
self.cart_write(0x0000, 0x00)
|
|
1885
|
-
self.cart_write(0x0000, 0x0D)
|
|
1886
|
-
|
|
1887
|
-
self.cart_write(0x0000, 0x0B)
|
|
1888
|
-
self.cart_write(0xA000, 0x61)
|
|
1889
|
-
self.cart_write(0x0000, 0x0D)
|
|
1890
|
-
self.cart_write(0xA000, 0xFE)
|
|
1891
|
-
self.cart_write(0x0000, 0x00)
|
|
1892
|
-
|
|
1893
|
-
elif self.MODE == "AGB":
|
|
1894
|
-
if bank > 0:
|
|
1895
|
-
if (save_type == 8) and bank > 0: # 1M SRAM
|
|
1896
|
-
self.gbx_flash_write_address_byte(0x1000000, 0)
|
|
1897
|
-
elif (save_type == 4 or save_type == 5) and bank > 0: # FLASH
|
|
1898
|
-
self.set_number(0, self.DEVICE_CMD["GBA_FLASH_SET_BANK"])
|
|
1899
|
-
|
|
1900
|
-
if mode == 2:
|
|
1901
|
-
if args["path"] is not None:
|
|
1902
|
-
try:
|
|
1903
|
-
file = open(args["path"], "wb")
|
|
1904
|
-
except PermissionError:
|
|
1905
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"FlashGBX doesn’t have permission to access this file for writing:\n" + path, "abortable":False})
|
|
1906
|
-
return False
|
|
1907
|
-
file.write(data_dump)
|
|
1908
|
-
file.close()
|
|
1909
|
-
else:
|
|
1910
|
-
self.INFO["data"] = data_dump
|
|
1911
|
-
#file.close()
|
|
1912
|
-
self.INFO["file_crc32"] = zlib.crc32(data_dump) & 0xFFFFFFFF
|
|
1913
|
-
self.INFO["file_sha1"] = hashlib.sha1(data_dump).hexdigest()
|
|
1914
|
-
|
|
1915
|
-
if audio_low: self.set_mode(self.DEVICE_CMD["AUDIO_HIGH"])
|
|
1916
|
-
self.INFO["last_action"] = mode
|
|
1917
|
-
self.SetProgress({"action":"FINISHED"})
|
|
1918
|
-
|
|
1919
|
-
#########################################
|
|
1920
|
-
|
|
1921
|
-
elif mode == 4: # Flash ROM
|
|
1922
|
-
if self.MODE == "DMG":
|
|
1923
|
-
supported_carts = list(self.SUPPORTED_CARTS['DMG'].values())
|
|
1924
|
-
i_size = 0x4000
|
|
1925
|
-
elif self.MODE == "AGB":
|
|
1926
|
-
supported_carts = list(self.SUPPORTED_CARTS['AGB'].values())
|
|
1927
|
-
i_size = 0x10000
|
|
1928
|
-
|
|
1929
|
-
if not isinstance(args["cart_type"], dict):
|
|
1930
|
-
cart_type = "RETAIL"
|
|
1931
|
-
for i in range(0, len(supported_carts)):
|
|
1932
|
-
if i == args["cart_type"]: cart_type = supported_carts[i]
|
|
1933
|
-
if cart_type == "RETAIL": return False # Generic ROM Cartridge is not flashable
|
|
1934
|
-
else:
|
|
1935
|
-
cart_type = args["cart_type"]
|
|
1936
|
-
|
|
1937
|
-
if path != "":
|
|
1938
|
-
with open(path, "rb") as file: data_import = file.read()
|
|
1939
|
-
else:
|
|
1940
|
-
data_import = args["buffer"]
|
|
1941
|
-
|
|
1942
|
-
# pad to next possible size
|
|
1943
|
-
i = i_size
|
|
1944
|
-
while len(data_import) > i: i += i_size
|
|
1945
|
-
i = i - len(data_import)
|
|
1946
|
-
if i > 0: data_import += bytearray([0xFF] * i)
|
|
1947
|
-
|
|
1948
|
-
self._FlashROM(buffer=data_import, cart_type=cart_type, voltage=args["override_voltage"], start_addr=0, signal=signal, prefer_chip_erase=args["prefer_chip_erase"], fast_read_mode=False, verify_write=args["verify_write"], fix_header=args["fix_header"], manual_mbc=args["mbc"])
|
|
1949
|
-
|
|
1950
|
-
# Reset pins to avoid save data loss
|
|
1951
|
-
self.set_mode(self.DEVICE_CMD["SET_PINS_AS_INPUTS"])
|
|
1952
|
-
return True
|
|
1953
|
-
|
|
1954
|
-
#######################################################################################################################################
|
|
1955
|
-
|
|
1956
|
-
def _FlashROM(self, buffer=bytearray(), start_addr=0, cart_type=None, voltage=3.3, signal=None, prefer_chip_erase=False, fast_read_mode=False, verify_write=False, fix_header=False, manual_mbc=0):
|
|
1957
|
-
if not self.IsConnected(): raise ConnectionError("Couldn’t access the the device.")
|
|
1958
|
-
if self.INFO == None: self.ReadInfo()
|
|
1959
|
-
self.INFO["last_action"] = 4
|
|
1960
|
-
bank_size = 0x4000
|
|
1961
|
-
time_start = time.time()
|
|
1962
|
-
|
|
1963
|
-
data_import = copy.copy(buffer)
|
|
1964
|
-
if start_addr > 0:
|
|
1965
|
-
data_import = (b'\xFF' * start_addr) + data_import
|
|
1966
|
-
data_import = bytearray(data_import)
|
|
1967
|
-
|
|
1968
|
-
if cart_type == "RETAIL": return False # Generic ROM Cartridge is not flashable
|
|
1969
|
-
flashcart_meta = copy.deepcopy(cart_type)
|
|
1970
|
-
|
|
1971
|
-
# Fix header
|
|
1972
|
-
if fix_header:
|
|
1973
|
-
if self.MODE == "DMG":
|
|
1974
|
-
temp = RomFileDMG(data_import[0:0x200]).FixHeader()
|
|
1975
|
-
elif self.MODE == "AGB":
|
|
1976
|
-
temp = RomFileAGB(data_import[0:0x200]).FixHeader()
|
|
1977
|
-
data_import[0:0x200] = temp
|
|
1978
|
-
|
|
1979
|
-
# Special carts
|
|
1980
|
-
if "Retrostage GameBoy Blaster" in cart_type["names"]:
|
|
1981
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The Retrostage GameBoy Blaster cartridge is currently not fully supported by FlashGBX. However, you can use the insideGadgets “Flasher” software available from <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a> to flash this cartridge.", "abortable":False})
|
|
1982
|
-
return False
|
|
1983
|
-
elif "insideGadgets Power Cart 1 MB, 128 KB SRAM" in cart_type["names"]:
|
|
1984
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The insideGadgets Power Cart is currently not fully supported by FlashGBX. However, you can use the dedicated insideGadgets “iG Power Cart Programs” software available from <a href=\"https://www.gbxcart.com/\">https://www.gbxcart.com/</a> to flash this cartridge.", "abortable":False})
|
|
1985
|
-
return False
|
|
1986
|
-
elif "power_cycle" in cart_type and cart_type["power_cycle"] is True and not self.CanPowerCycleCart():
|
|
1987
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is not flashable using FlashGBX and your GBxCart RW hardware revision due to missing cartridge power cycling support.", "abortable":False})
|
|
1988
|
-
return False
|
|
1989
|
-
# Special carts
|
|
1990
|
-
# Firmware check R20+
|
|
1991
|
-
if (int(self.FW[0]) < 20) and self.MODE == "AGB" and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xAA], [0x555, 0x55], ['SA', 0x25], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x29]]:
|
|
1992
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"A firmware update is required to access this cartridge. Please update the firmware of your GBxCart RW device to version R20 or higher.", "abortable":False})
|
|
1993
|
-
return False
|
|
1994
|
-
# Firmware check R20+
|
|
1995
|
-
# Firmware check R23+
|
|
1996
|
-
if (int(self.FW[0]) < 23) and self.MODE == "AGB" and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xA9], [0x555, 0x56], ['SA', 0x26], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x2A]]:
|
|
1997
|
-
print("NOTE: Update your GBxCart RW firmware to version R23 or higher for a better transfer rate with this cartridge.")
|
|
1998
|
-
del flashcart_meta["commands"]["buffer_write"]
|
|
1999
|
-
# Firmware check R23+
|
|
2000
|
-
# Firmware check R25+
|
|
2001
|
-
if self.MODE == "AGB" and "single_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["single_write"] == [['PA', 0x70], ['PA', 0x10], ['PA', 'PD']] and (([ 0xB0, 0x00, 0xE2, 0x00 ] in flashcart_meta["flash_ids"]) or ([ 0xB0, 0x00, 0xB0, 0x00 ] in flashcart_meta["flash_ids"])): # Dev
|
|
2002
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
|
|
2003
|
-
return False
|
|
2004
|
-
# Firmware check R25+
|
|
2005
|
-
# Firmware check R28+
|
|
2006
|
-
if (int(self.FW[0]) >= 28) and self.MODE == "AGB" and ("flash_ids" in flashcart_meta and ([ 0x89, 0x00, 0x89, 0x00, 0x18, 0x00, 0x18, 0x00 ] in flashcart_meta["flash_ids"])): # Flash2Advance
|
|
2007
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
|
|
2008
|
-
return False
|
|
2009
|
-
# Firmware check R25+
|
|
2010
|
-
# Firmware check
|
|
2011
|
-
if self.MODE == "AGB" and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] == [['SA', 0xEA], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
|
2012
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
|
|
2013
|
-
return False
|
|
2014
|
-
if self.MODE == "AGB" and "buffer_size" in flashcart_meta and flashcart_meta["buffer_size"] > 256:
|
|
2015
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please check for firmware updates in the “Tools” menu or the maker’s website.".format(APPNAME, self.GetFullName()), "abortable":False})
|
|
2016
|
-
return False
|
|
2017
|
-
if self.MODE == "DMG" and "single_write" in flashcart_meta["commands"] and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] != [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
|
2018
|
-
print("NOTE: Update your GBxCart RW firmware to version L1 or higher for a better transfer rate with this cartridge.")
|
|
2019
|
-
del flashcart_meta["commands"]["buffer_write"]
|
|
2020
|
-
elif self.MODE == "AGB" and "single_write" in flashcart_meta["commands"] and "buffer_write" in flashcart_meta["commands"] and flashcart_meta["commands"]["buffer_write"] != [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
|
2021
|
-
print("NOTE: Update your GBxCart RW firmware to version L1 or higher for a better transfer rate with this cartridge.")
|
|
2022
|
-
del flashcart_meta["commands"]["buffer_write"]
|
|
2023
|
-
|
|
2024
|
-
if "flash_commands_on_bank_1" in cart_type:
|
|
2025
|
-
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})
|
|
2026
|
-
return False
|
|
2027
|
-
|
|
2028
|
-
# Set Voltage
|
|
2029
|
-
if voltage == 3.3:
|
|
2030
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
|
2031
|
-
elif voltage == 5:
|
|
2032
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
2033
|
-
elif flashcart_meta["voltage"] == 3.3:
|
|
2034
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_3_3V"])
|
|
2035
|
-
elif flashcart_meta["voltage"] == 5:
|
|
2036
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
2037
|
-
|
|
2038
|
-
if self.MODE == "DMG":
|
|
2039
|
-
# MBC
|
|
2040
|
-
if "mbc" in flashcart_meta:
|
|
2041
|
-
mbc = flashcart_meta["mbc"]
|
|
2042
|
-
if mbc is not False and isinstance(mbc, int):
|
|
2043
|
-
dprint("Using forced mapper type 0x{:02X} for flashing".format(mbc))
|
|
2044
|
-
elif mbc == "manual":
|
|
2045
|
-
mbc = manual_mbc
|
|
2046
|
-
dprint("Using manually selected mapper type 0x{:02X} for flashing".format(mbc))
|
|
2047
|
-
if mbc == 0:
|
|
2048
|
-
mbc = 0x19 # MBC5 default
|
|
2049
|
-
dprint("Using default mapper type 0x{:02X} for flashing".format(mbc))
|
|
2050
|
-
else:
|
|
2051
|
-
mbc = 0x19 # MBC5 default
|
|
2052
|
-
|
|
2053
|
-
self.set_mode(self.DEVICE_CMD["GB_CART_MODE"])
|
|
2054
|
-
if "flash_commands_on_bank_1" in flashcart_meta and flashcart_meta["flash_commands_on_bank_1"]:
|
|
2055
|
-
dprint("Setting GB_FLASH_BANK_1_COMMAND_WRITES")
|
|
2056
|
-
self.set_mode(self.DEVICE_CMD["GB_FLASH_BANK_1_COMMAND_WRITES"])
|
|
2057
|
-
|
|
2058
|
-
self.set_mode(self.DEVICE_CMD["GB_FLASH_WE_PIN"])
|
|
2059
|
-
if flashcart_meta["write_pin"] == "WR":
|
|
2060
|
-
dprint("Setting WE_AS_WR_PIN")
|
|
2061
|
-
self.set_mode(self.DEVICE_CMD["WE_AS_WR_PIN"])
|
|
2062
|
-
elif flashcart_meta["write_pin"] in ("AUDIO", "VIN"):
|
|
2063
|
-
dprint("Setting WE_AS_AUDIO_PIN")
|
|
2064
|
-
self.set_mode(self.DEVICE_CMD["WE_AS_AUDIO_PIN"])
|
|
2065
|
-
|
|
2066
|
-
if "single_write" in flashcart_meta["commands"] and len(flashcart_meta["commands"]["single_write"]) == 4:
|
|
2067
|
-
# Submit flash program commands to firmware
|
|
2068
|
-
dprint("Setting GB_FLASH_PROGRAM_METHOD")
|
|
2069
|
-
self.set_mode(self.DEVICE_CMD["GB_FLASH_PROGRAM_METHOD"])
|
|
2070
|
-
for i in range(0, 3):
|
|
2071
|
-
dprint("single_write_command(",i,"):", hex(flashcart_meta["commands"]["single_write"][i][0]), "=", hex(flashcart_meta["commands"]["single_write"][i][1]))
|
|
2072
|
-
self.write(bytearray(format(flashcart_meta["commands"]["single_write"][i][0], "x"), "ascii") + b'\x00', True)
|
|
2073
|
-
self.write(bytearray(format(flashcart_meta["commands"]["single_write"][i][1], "x"), "ascii") + b'\x00', True)
|
|
2074
|
-
|
|
2075
|
-
elif self.MODE == "AGB":
|
|
2076
|
-
# Read a bit of ROM before starting
|
|
2077
|
-
self.ReadROM(0, 64)
|
|
2078
|
-
|
|
2079
|
-
# Unlock Flash
|
|
2080
|
-
if "unlock" in flashcart_meta["commands"]:
|
|
2081
|
-
for i in range(0, len(flashcart_meta["commands"]["unlock"])):
|
|
2082
|
-
addr = flashcart_meta["commands"]["unlock"][i][0]
|
|
2083
|
-
data = flashcart_meta["commands"]["unlock"][i][1]
|
|
2084
|
-
count = flashcart_meta["commands"]["unlock"][i][2]
|
|
2085
|
-
for j in range(0, count):
|
|
2086
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
2087
|
-
|
|
2088
|
-
# Reset Flash
|
|
2089
|
-
if "reset" in flashcart_meta["commands"]:
|
|
2090
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
2091
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
2092
|
-
|
|
2093
|
-
# Read sector size from CFI if necessary
|
|
2094
|
-
if "sector_size_from_cfi" in flashcart_meta and flashcart_meta["sector_size_from_cfi"] is True:
|
|
2095
|
-
(_, cfi_s, cfi) = self.CheckFlashChip(limitVoltage=(voltage == 3.3), cart_type=cart_type)
|
|
2096
|
-
if cfi_s == "":
|
|
2097
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Couldn’t read the Common Flash Interface (CFI) data from the flash chip in order to determine the correct sector size map. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.", "abortable":False})
|
|
2098
|
-
return False
|
|
2099
|
-
flashcart_meta["sector_size"] = cfi["erase_sector_blocks"]
|
|
2100
|
-
if cfi["tb_boot_sector_raw"] == 0x03: flashcart_meta['sector_size'].reverse()
|
|
2101
|
-
dprint("Sector map was read from Common Flash Interface (CFI) data:", cfi["erase_sector_blocks"], cfi["erase_sector_blocks"])
|
|
2102
|
-
self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2103
|
-
|
|
2104
|
-
# Check if write command exists and quit if not
|
|
2105
|
-
if "single_write" not in flashcart_meta["commands"] and "buffer_write" not in flashcart_meta["commands"]:
|
|
2106
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge type is currently not supported for ROM writing using the current firmware version. However, a new firmware version might work which may be available in GUI mode from the “Tools” menu.", "abortable":False})
|
|
2107
|
-
return False
|
|
2108
|
-
|
|
2109
|
-
# Chip Erase
|
|
2110
|
-
chip_erase = False
|
|
2111
|
-
if "chip_erase" in flashcart_meta["commands"]:
|
|
2112
|
-
if "sector_erase" in flashcart_meta["commands"] and prefer_chip_erase is False:
|
|
2113
|
-
chip_erase = False
|
|
2114
|
-
elif "chip_erase_treshold" in flashcart_meta:
|
|
2115
|
-
if len(data_import) > flashcart_meta["chip_erase_treshold"] or "sector_erase" not in flashcart_meta["commands"]:
|
|
2116
|
-
chip_erase = True
|
|
2117
|
-
else:
|
|
2118
|
-
chip_erase = True
|
|
2119
|
-
self.SetProgress({"action":"ERASE", "time_start":time_start, "abortable":False})
|
|
2120
|
-
for i in range(0, len(flashcart_meta["commands"]["chip_erase"])):
|
|
2121
|
-
addr = flashcart_meta["commands"]["chip_erase"][i][0]
|
|
2122
|
-
data = flashcart_meta["commands"]["chip_erase"][i][1]
|
|
2123
|
-
if not addr == None:
|
|
2124
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
2125
|
-
if flashcart_meta["commands"]["chip_erase_wait_for"][i][0] != None:
|
|
2126
|
-
addr = flashcart_meta["commands"]["chip_erase_wait_for"][i][0]
|
|
2127
|
-
data = flashcart_meta["commands"]["chip_erase_wait_for"][i][1]
|
|
2128
|
-
timeout = flashcart_meta["chip_erase_timeout"]
|
|
2129
|
-
while True:
|
|
2130
|
-
self.SetProgress({"action":"ERASE", "time_start":time_start, "abortable":False})
|
|
2131
|
-
if "wait_read_status_register" in flashcart_meta and flashcart_meta["wait_read_status_register"]:
|
|
2132
|
-
for j in range(0, len(flashcart_meta["commands"]["read_status_register"])):
|
|
2133
|
-
sr_addr = flashcart_meta["commands"]["read_status_register"][j][0]
|
|
2134
|
-
sr_data = flashcart_meta["commands"]["read_status_register"][j][1]
|
|
2135
|
-
self.gbx_flash_write_address_byte(sr_addr, sr_data)
|
|
2136
|
-
wait_for = self.ReadROM(addr, 64)
|
|
2137
|
-
wait_for = ((wait_for[1] << 8 | wait_for[0]) & flashcart_meta["commands"]["chip_erase_wait_for"][i][2])
|
|
2138
|
-
dprint("CE_SR {:X}=={:X}?".format(wait_for, data))
|
|
2139
|
-
if wait_for == data: break
|
|
2140
|
-
time.sleep(0.5)
|
|
2141
|
-
timeout -= 0.5
|
|
2142
|
-
if timeout <= 0:
|
|
2143
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Erasing the flash chip timed out. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.", "abortable":False})
|
|
2144
|
-
return False
|
|
2145
|
-
|
|
2146
|
-
# Reset Flash
|
|
2147
|
-
if "reset" in flashcart_meta["commands"]:
|
|
2148
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
2149
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
2150
|
-
|
|
2151
|
-
dprint("Chip erase took {:d} seconds".format(math.ceil(time.time() - time_start)))
|
|
2152
|
-
|
|
2153
|
-
elif "sector_erase" in flashcart_meta["commands"] and "flash_size" in flashcart_meta and prefer_chip_erase is True:
|
|
2154
|
-
flash_size = flashcart_meta["flash_size"]
|
|
2155
|
-
if flash_size is not False and len(data_import) < flash_size:
|
|
2156
|
-
# Pad with FF till the end
|
|
2157
|
-
data_import += bytearray([0xFF] * (flash_size - len(data_import)))
|
|
2158
|
-
|
|
2159
|
-
self.set_number(0, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2160
|
-
|
|
2161
|
-
# Write Flash
|
|
2162
|
-
pos = 0
|
|
2163
|
-
currAddr = 0
|
|
2164
|
-
skipping = False # skips if block is full of 0xFF
|
|
2165
|
-
if self.MODE == "DMG":
|
|
2166
|
-
if "first_bank" in flashcart_meta: first_bank = flashcart_meta["first_bank"]
|
|
2167
|
-
if "start_addr" in flashcart_meta: currAddr = flashcart_meta["start_addr"]
|
|
2168
|
-
endAddr = 0x7FFF
|
|
2169
|
-
bank_count = math.ceil(len(data_import) / bank_size)
|
|
2170
|
-
if start_addr == 0: self.SetBankROM(0, mbc=mbc, bank_count=bank_count)
|
|
2171
|
-
elif self.MODE == "AGB":
|
|
2172
|
-
currAddr = 0
|
|
2173
|
-
endAddr = len(data_import)
|
|
2174
|
-
first_bank = 0
|
|
2175
|
-
bank_count = 1
|
|
2176
|
-
|
|
2177
|
-
self.SetProgress({"action":"INITIALIZE", "time_start":time.time(), "method":"ROM_WRITE", "size":len(data_import)})
|
|
2178
|
-
|
|
2179
|
-
currSect = 0
|
|
2180
|
-
|
|
2181
|
-
# Fast Forward
|
|
2182
|
-
if start_addr > 0:
|
|
2183
|
-
first_bank = math.floor(start_addr / bank_size)
|
|
2184
|
-
self.SetBankROM(first_bank, mbc=mbc, bank_count=bank_count)
|
|
2185
|
-
offset = start_addr % bank_size
|
|
2186
|
-
currAddr = bank_size + offset
|
|
2187
|
-
if "sector_erase" in flashcart_meta["commands"]:
|
|
2188
|
-
while pos < start_addr:
|
|
2189
|
-
dprint("* currSect:",currSect)
|
|
2190
|
-
dprint("sector_size:", hex(flashcart_meta["sector_size"][currSect][0]))
|
|
2191
|
-
dprint("start_addr:",hex(start_addr),", pos:",hex(pos))
|
|
2192
|
-
pos += flashcart_meta["sector_size"][currSect][0]
|
|
2193
|
-
flashcart_meta["sector_size"][currSect][1] -= 1
|
|
2194
|
-
if flashcart_meta["sector_size"][currSect][1] == 0:
|
|
2195
|
-
currSect += 1
|
|
2196
|
-
dprint("currSect:", currSect, end=", ")
|
|
2197
|
-
dprint(flashcart_meta["sector_size"])
|
|
2198
|
-
dprint(flashcart_meta["sector_size"][currSect][1])
|
|
2199
|
-
|
|
2200
|
-
sector_count = None
|
|
2201
|
-
sector_size = 0
|
|
2202
|
-
if "sector_erase" in flashcart_meta["commands"]:
|
|
2203
|
-
if isinstance(flashcart_meta["sector_size"], list):
|
|
2204
|
-
sector_size = flashcart_meta["sector_size"][currSect][0]
|
|
2205
|
-
else:
|
|
2206
|
-
sector_size = flashcart_meta["sector_size"]
|
|
2207
|
-
dprint("sector_size:", sector_size)
|
|
2208
|
-
|
|
2209
|
-
dprint("start_addr:", hex(start_addr))
|
|
2210
|
-
dprint("first_bank:", first_bank, ", bank_count:", bank_count)
|
|
2211
|
-
dprint("currAddr:", hex(currAddr), ", endAddr:", hex(endAddr))
|
|
2212
|
-
dprint("pos:", hex(pos))
|
|
2213
|
-
|
|
2214
|
-
ack = True
|
|
2215
|
-
if first_bank == bank_count: first_bank -= 1 # dirty hack so that <32 KB works too
|
|
2216
|
-
for bank in range(first_bank, bank_count):
|
|
2217
|
-
if self.MODE == "DMG":
|
|
2218
|
-
if bank > first_bank: currAddr = bank_size
|
|
2219
|
-
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2220
|
-
|
|
2221
|
-
while (currAddr < endAddr):
|
|
2222
|
-
if pos >= len(data_import): break
|
|
2223
|
-
if self.CANCEL:
|
|
2224
|
-
# Reset Flash
|
|
2225
|
-
if "reset" in flashcart_meta["commands"]:
|
|
2226
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
2227
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
2228
|
-
cancel_args = {"action":"ABORT", "abortable":False}
|
|
2229
|
-
cancel_args.update(self.CANCEL_ARGS)
|
|
2230
|
-
self.CANCEL_ARGS = {}
|
|
2231
|
-
self.SetProgress(cancel_args)
|
|
2232
|
-
return
|
|
2233
|
-
|
|
2234
|
-
if self.MODE == "DMG":
|
|
2235
|
-
# Change Bank
|
|
2236
|
-
if (currAddr == bank_size):
|
|
2237
|
-
# Reset Flash
|
|
2238
|
-
if "reset" in flashcart_meta["commands"]:
|
|
2239
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
2240
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
2241
|
-
self.SetBankROM(bank, mbc=mbc, bank_count=bank_count)
|
|
2242
|
-
time.sleep(0.05)
|
|
2243
|
-
|
|
2244
|
-
# Sector Erase (if supported)
|
|
2245
|
-
if "sector_erase" in flashcart_meta["commands"] and not chip_erase:
|
|
2246
|
-
if isinstance(flashcart_meta["sector_size"], list):
|
|
2247
|
-
if sector_count == None:
|
|
2248
|
-
sector_count = flashcart_meta["sector_size"][currSect][1]
|
|
2249
|
-
if sector_count == 0:
|
|
2250
|
-
if ((currSect+1) != len(flashcart_meta["sector_size"])):
|
|
2251
|
-
currSect += 1
|
|
2252
|
-
sector_count = flashcart_meta["sector_size"][currSect][1]
|
|
2253
|
-
|
|
2254
|
-
if pos % sector_size == 0:
|
|
2255
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":pos})
|
|
2256
|
-
self.SetProgress({"action":"SECTOR_ERASE", "sector_size":sector_size, "sector_pos":pos, "time_start":time.time(), "abortable":True})
|
|
2257
|
-
|
|
2258
|
-
# Update sector size if changed
|
|
2259
|
-
if "sector_erase" in flashcart_meta["commands"]:
|
|
2260
|
-
if isinstance(flashcart_meta["sector_size"], list):
|
|
2261
|
-
sector_size = flashcart_meta["sector_size"][currSect][0]
|
|
2262
|
-
dprint("* sector_count:", sector_count, "sector_size:", hex(sector_size), "pos:",hex(pos))
|
|
2263
|
-
|
|
2264
|
-
for i in range(0, len(flashcart_meta["commands"]["sector_erase"])):
|
|
2265
|
-
addr = flashcart_meta["commands"]["sector_erase"][i][0]
|
|
2266
|
-
data = flashcart_meta["commands"]["sector_erase"][i][1]
|
|
2267
|
-
if addr == "SA": addr = currAddr
|
|
2268
|
-
if addr == "SA+1": addr = currAddr + 1
|
|
2269
|
-
if addr == "SA+2": addr = currAddr + 2
|
|
2270
|
-
if addr == "SA+0x4000": addr = currAddr + 0x4000
|
|
2271
|
-
if addr == "SA+0x7000": addr = currAddr + 0x7000
|
|
2272
|
-
if not addr == None:
|
|
2273
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
2274
|
-
dprint("SE {:08X}={:X}".format(addr, data))
|
|
2275
|
-
if flashcart_meta["commands"]["sector_erase_wait_for"][i][0] != None:
|
|
2276
|
-
addr = flashcart_meta["commands"]["sector_erase_wait_for"][i][0]
|
|
2277
|
-
data = flashcart_meta["commands"]["sector_erase_wait_for"][i][1]
|
|
2278
|
-
if addr == "SA": addr = currAddr
|
|
2279
|
-
if addr == "SA+1": addr = currAddr + 1
|
|
2280
|
-
if addr == "SA+2": addr = currAddr + 2
|
|
2281
|
-
if addr == "SA+0x4000": addr = currAddr + 0x4000
|
|
2282
|
-
if addr == "SA+0x7000": addr = currAddr + 0x7000
|
|
2283
|
-
time.sleep(0.05)
|
|
2284
|
-
timeout = 100
|
|
2285
|
-
while True:
|
|
2286
|
-
if "wait_read_status_register" in flashcart_meta and flashcart_meta["wait_read_status_register"] == True:
|
|
2287
|
-
for j in range(0, len(flashcart_meta["commands"]["read_status_register"])):
|
|
2288
|
-
sr_addr = flashcart_meta["commands"]["read_status_register"][j][0]
|
|
2289
|
-
sr_data = flashcart_meta["commands"]["read_status_register"][j][1]
|
|
2290
|
-
self.gbx_flash_write_address_byte(sr_addr, sr_data)
|
|
2291
|
-
dprint("SE_SR {:08X}={:X}".format(addr, data))
|
|
2292
|
-
wait_for = self.ReadROM(currAddr, 64)
|
|
2293
|
-
wait_for = ((wait_for[1] << 8 | wait_for[0]) & flashcart_meta["commands"]["sector_erase_wait_for"][i][2])
|
|
2294
|
-
dprint("SE_SR {:X}=={:X}?".format(wait_for, data))
|
|
2295
|
-
time.sleep(0.1)
|
|
2296
|
-
timeout -= 1
|
|
2297
|
-
if timeout < 1:
|
|
2298
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Erasing a flash chip sector timed out. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.", "abortable":False})
|
|
2299
|
-
return False
|
|
2300
|
-
if wait_for == data: break
|
|
2301
|
-
self.SetProgress({"action":"SECTOR_ERASE", "sector_size":sector_size, "sector_pos":pos, "time_start":time.time(), "abortable":True})
|
|
2302
|
-
|
|
2303
|
-
# Reset Flash
|
|
2304
|
-
if "reset" in flashcart_meta["commands"]:
|
|
2305
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
2306
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
2307
|
-
|
|
2308
|
-
if self.MODE == "DMG":
|
|
2309
|
-
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2310
|
-
elif self.MODE == "AGB":
|
|
2311
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2312
|
-
|
|
2313
|
-
if sector_count is not None:
|
|
2314
|
-
sector_count -= 1
|
|
2315
|
-
|
|
2316
|
-
# Write data (with special firmware acceleration if available)
|
|
2317
|
-
if "buffer_write" in flashcart_meta["commands"]:
|
|
2318
|
-
if self.MODE == "DMG":
|
|
2319
|
-
# BUNG Doctor GB Card 64M
|
|
2320
|
-
if flashcart_meta["commands"]["buffer_write"] == [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
|
2321
|
-
data = data_import[pos:pos+32]
|
|
2322
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2323
|
-
skipping = True
|
|
2324
|
-
else:
|
|
2325
|
-
if skipping:
|
|
2326
|
-
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2327
|
-
skipping = False
|
|
2328
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_INTEL_BUFFERED_32BYTE"], data)
|
|
2329
|
-
ack = self.wait_for_ack()
|
|
2330
|
-
currAddr += 32
|
|
2331
|
-
pos += 32
|
|
2332
|
-
|
|
2333
|
-
else:
|
|
2334
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Buffer writing for this flash chip is not supported with your device’s firmware version. You can a newer firmware version which is available through the firmware updater in the “Tools” menu.\n\n{:s}".format(str(flashcart_meta["commands"]["buffer_write"])), "abortable":False})
|
|
2335
|
-
return False
|
|
2336
|
-
|
|
2337
|
-
elif self.MODE == "AGB":
|
|
2338
|
-
# Flash2Advance 256M
|
|
2339
|
-
if flashcart_meta["commands"]["buffer_write"] == [['SA', 0xE8], ['SA+2', 0xE8], ['SA', 'BS'], ['SA+2', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA+2', 0xD0], [None, None], [None, None]]:
|
|
2340
|
-
data = data_import[pos:pos+256]
|
|
2341
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2342
|
-
skipping = True
|
|
2343
|
-
else:
|
|
2344
|
-
if skipping:
|
|
2345
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2346
|
-
skipping = False
|
|
2347
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_INTERLEAVED_256BYTE"], data)
|
|
2348
|
-
ack = self.wait_for_ack()
|
|
2349
|
-
currAddr += 256
|
|
2350
|
-
pos += 256
|
|
2351
|
-
|
|
2352
|
-
# 256L30B, M36L0R etc.
|
|
2353
|
-
elif flashcart_meta["commands"]["buffer_write"] == [['SA', 0xE8], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0xD0], ['SA', 0xFF]]:
|
|
2354
|
-
if "single_write_7FC0_to_7FFF" in flashcart_meta and flashcart_meta["single_write_7FC0_to_7FFF"] and int(currAddr % 0x8000) in range(0x7FC0, 0x7FFF):
|
|
2355
|
-
for i in range(0, len(flashcart_meta["commands"]["single_write"])):
|
|
2356
|
-
addr = flashcart_meta["commands"]["single_write"][i][0]
|
|
2357
|
-
data = flashcart_meta["commands"]["single_write"][i][1]
|
|
2358
|
-
if addr == "PA": addr = int(currAddr)
|
|
2359
|
-
if data == "PD": data = struct.unpack('H', data_import[pos:pos+2])[0]
|
|
2360
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
2361
|
-
currAddr += 2
|
|
2362
|
-
pos += 2
|
|
2363
|
-
data = data_import[pos:pos+2]
|
|
2364
|
-
|
|
2365
|
-
if int(currAddr % 0x8000) == 0:
|
|
2366
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2367
|
-
|
|
2368
|
-
# Firmware check R24+
|
|
2369
|
-
elif (int(self.FW[0]) >= 24) and "single_write_7FC0_to_7FFF" not in flashcart_meta:
|
|
2370
|
-
data = data_import[pos:pos+256]
|
|
2371
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2372
|
-
skipping = True
|
|
2373
|
-
else:
|
|
2374
|
-
if skipping:
|
|
2375
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2376
|
-
skipping = False
|
|
2377
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_256BYTE"], data)
|
|
2378
|
-
ack = self.wait_for_ack()
|
|
2379
|
-
|
|
2380
|
-
currAddr += 256
|
|
2381
|
-
pos += 256
|
|
2382
|
-
|
|
2383
|
-
else:
|
|
2384
|
-
data = data_import[pos:pos+64]
|
|
2385
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2386
|
-
skipping = True
|
|
2387
|
-
else:
|
|
2388
|
-
if skipping:
|
|
2389
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2390
|
-
skipping = False
|
|
2391
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_64BYTE"], data)
|
|
2392
|
-
ack = self.wait_for_ack()
|
|
2393
|
-
|
|
2394
|
-
currAddr += 64
|
|
2395
|
-
pos += 64
|
|
2396
|
-
|
|
2397
|
-
# MSP55LV128M etc.
|
|
2398
|
-
elif flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xA9], [0x555, 0x56], ['SA', 0x26], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x2A]]:
|
|
2399
|
-
data = data_import[pos:pos+256]
|
|
2400
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2401
|
-
skipping = True
|
|
2402
|
-
else:
|
|
2403
|
-
if skipping:
|
|
2404
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2405
|
-
skipping = False
|
|
2406
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BUFFERED_256BYTE_SWAPPED_D0D1"], data)
|
|
2407
|
-
ack = self.wait_for_ack()
|
|
2408
|
-
currAddr += 256
|
|
2409
|
-
pos += 256
|
|
2410
|
-
|
|
2411
|
-
# insideGadgets flash carts etc.
|
|
2412
|
-
elif flashcart_meta["commands"]["buffer_write"] == [[0xAAA, 0xAA], [0x555, 0x55], ['SA', 0x25], ['SA', 'BS'], ['PA', 'PD'], ['SA', 0x29]]:
|
|
2413
|
-
if "single_write_first_256_bytes" in flashcart_meta and flashcart_meta["single_write_first_256_bytes"] and currAddr < 256:
|
|
2414
|
-
for i in range(0, len(flashcart_meta["commands"]["single_write"])):
|
|
2415
|
-
addr = flashcart_meta["commands"]["single_write"][i][0]
|
|
2416
|
-
data = flashcart_meta["commands"]["single_write"][i][1]
|
|
2417
|
-
if addr == "PA": addr = int(currAddr)
|
|
2418
|
-
if data == "PD": data = struct.unpack('H', data_import[pos:pos+2])[0]
|
|
2419
|
-
self.gbx_flash_write_address_byte(addr, data)
|
|
2420
|
-
currAddr += 2
|
|
2421
|
-
pos += 2
|
|
2422
|
-
data = data_import[pos:pos+2]
|
|
2423
|
-
|
|
2424
|
-
if currAddr == 256:
|
|
2425
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2426
|
-
|
|
2427
|
-
else:
|
|
2428
|
-
data = data_import[pos:pos+256]
|
|
2429
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2430
|
-
skipping = True
|
|
2431
|
-
else:
|
|
2432
|
-
if skipping:
|
|
2433
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2434
|
-
skipping = False
|
|
2435
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_BUFFERED_256BYTE"], data)
|
|
2436
|
-
ack = self.wait_for_ack()
|
|
2437
|
-
currAddr += 256
|
|
2438
|
-
pos += 256
|
|
2439
|
-
|
|
2440
|
-
else:
|
|
2441
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Buffer writing for this flash chip is not supported with your device’s firmware version. You can try a newer firmware version which is available through the firmware updater in the “Tools” menu.\n\n{:s}".format(str(flashcart_meta["commands"]["buffer_write"])), "abortable":False})
|
|
2442
|
-
return False
|
|
2443
|
-
|
|
2444
|
-
elif "single_write" in flashcart_meta["commands"]:
|
|
2445
|
-
if self.MODE == "DMG":
|
|
2446
|
-
# Firmware check R24+
|
|
2447
|
-
if (int(self.FW[0]) < 24) or ("pulse_reset_after_write" in flashcart_meta and flashcart_meta["pulse_reset_after_write"]):
|
|
2448
|
-
data = data_import[pos:pos+64]
|
|
2449
|
-
else:
|
|
2450
|
-
data = data_import[pos:pos+256]
|
|
2451
|
-
|
|
2452
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2453
|
-
skipping = True
|
|
2454
|
-
else:
|
|
2455
|
-
if skipping:
|
|
2456
|
-
self.set_number(currAddr, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2457
|
-
skipping = False
|
|
2458
|
-
if "pulse_reset_after_write" in flashcart_meta and flashcart_meta["pulse_reset_after_write"]:
|
|
2459
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_64BYTE_PULSE_RESET"], data)
|
|
2460
|
-
elif len(data) == 64:
|
|
2461
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_64BYTE"], data)
|
|
2462
|
-
elif len(data) == 256:
|
|
2463
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GB_FLASH_WRITE_UNBUFFERED_256BYTE"], data)
|
|
2464
|
-
ack = self.wait_for_ack()
|
|
2465
|
-
|
|
2466
|
-
currAddr += len(data)
|
|
2467
|
-
pos += len(data)
|
|
2468
|
-
|
|
2469
|
-
elif self.MODE == "AGB":
|
|
2470
|
-
# MSP55LV128 etc.
|
|
2471
|
-
if flashcart_meta["commands"]["single_write"] == [[0xAAA, 0xA9], [0x555, 0x56], [0xAAA, 0xA0], ['PA', 'PD']]:
|
|
2472
|
-
data = data_import[pos:pos+256]
|
|
2473
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2474
|
-
skipping = True
|
|
2475
|
-
else:
|
|
2476
|
-
if skipping:
|
|
2477
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2478
|
-
skipping = False
|
|
2479
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_256BYTE_SWAPPED_D0D1"], data)
|
|
2480
|
-
ack = self.wait_for_ack()
|
|
2481
|
-
currAddr += 256
|
|
2482
|
-
pos += 256
|
|
2483
|
-
|
|
2484
|
-
# 128W30B0 etc.
|
|
2485
|
-
elif flashcart_meta["commands"]["single_write"] == [[ 0, 0x70 ], [ 0, 0x10 ], [ 'PA', 'PD' ]]:
|
|
2486
|
-
data = data_import[pos:pos+64]
|
|
2487
|
-
if data == bytearray([0xFF] * len(data)):
|
|
2488
|
-
skipping = True
|
|
2489
|
-
else:
|
|
2490
|
-
if skipping:
|
|
2491
|
-
self.set_number(currAddr / 2, self.DEVICE_CMD["SET_START_ADDRESS"])
|
|
2492
|
-
skipping = False
|
|
2493
|
-
self.gbx_flash_write_data_bytes(self.DEVICE_CMD["GBA_FLASH_WRITE_INTEL_64BYTE_WORD"], data)
|
|
2494
|
-
ack = self.wait_for_ack()
|
|
2495
|
-
currAddr += 64
|
|
2496
|
-
pos += 64
|
|
2497
|
-
|
|
2498
|
-
else: # super slow -- for testing purposes only!
|
|
2499
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"This cartridge is currently not supported by {:s} using the current firmware version of the {:s} device. Please try a differnt firmware version or newer hardware revision.".format(APPNAME, self.GetFullName()), "abortable":False})
|
|
2500
|
-
return False
|
|
2501
|
-
|
|
2502
|
-
if ack == False:
|
|
2503
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"Couldn’t write {:d} bytes to flash at position 0x{:X}. Please make sure that the cartridge contacts are clean, and that the selected cartridge type and settings are correct.".format(len(data), pos-len(data)), "abortable":False})
|
|
2504
|
-
return False
|
|
2505
|
-
else:
|
|
2506
|
-
if (skipping is False) and (isinstance(data, int) or data is None or data == b''):
|
|
2507
|
-
print(skipping, data)
|
|
2508
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"No flash commands available for this cartridge type. Please make sure that the selected cartridge type and settings are correct. ({:s})".format(str(data)), "abortable":False})
|
|
2509
|
-
return False
|
|
2510
|
-
else:
|
|
2511
|
-
self.SetProgress({"action":"WRITE", "bytes_added":len(data), "skipping":skipping})
|
|
2512
|
-
|
|
2513
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":pos})
|
|
2514
|
-
time.sleep(0.5)
|
|
2515
|
-
|
|
2516
|
-
# Reset Flash
|
|
2517
|
-
if "reset_every" in flashcart_meta:
|
|
2518
|
-
for j in range(0, pos, flashcart_meta["reset_every"]):
|
|
2519
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
2520
|
-
self.gbx_flash_write_address_byte(j, flashcart_meta["commands"]["reset"][i][1])
|
|
2521
|
-
elif "reset" in flashcart_meta["commands"]:
|
|
2522
|
-
for i in range(0, len(flashcart_meta["commands"]["reset"])):
|
|
2523
|
-
self.gbx_flash_write_address_byte(flashcart_meta["commands"]["reset"][i][0], flashcart_meta["commands"]["reset"][i][1])
|
|
2524
|
-
|
|
2525
|
-
# Verify Flash
|
|
2526
|
-
verified = False
|
|
2527
|
-
if verify_write:
|
|
2528
|
-
rom_size = len(data_import)
|
|
2529
|
-
buffer_len = 0x1000
|
|
2530
|
-
if self.MODE == "DMG":
|
|
2531
|
-
self.set_mode(self.DEVICE_CMD["VOLTAGE_5V"])
|
|
2532
|
-
if fast_read_mode:
|
|
2533
|
-
buffer_len = 0x4000
|
|
2534
|
-
self.FAST_READ = True
|
|
2535
|
-
elif self.MODE == "AGB":
|
|
2536
|
-
if fast_read_mode:
|
|
2537
|
-
buffer_len = 0x10000
|
|
2538
|
-
self.FAST_READ = True
|
|
2539
|
-
|
|
2540
|
-
startAddr = 0
|
|
2541
|
-
currAddr = 0
|
|
2542
|
-
pos = 0
|
|
2543
|
-
|
|
2544
|
-
if self.MODE == "DMG":
|
|
2545
|
-
endAddr = bank_size
|
|
2546
|
-
else:
|
|
2547
|
-
endAddr = rom_size
|
|
2548
|
-
bank_count = 1
|
|
2549
|
-
|
|
2550
|
-
# Read a bit before actually dumping (fixes some bootlegs)
|
|
2551
|
-
self.ReadROM(0, 64)
|
|
2552
|
-
|
|
2553
|
-
self.SetProgress({"action":"INITIALIZE", "method":"ROM_WRITE_VERIFY", "size":rom_size})
|
|
2554
|
-
|
|
2555
|
-
for bank in range(0, bank_count):
|
|
2556
|
-
if self.MODE == "DMG":
|
|
2557
|
-
if bank > 0:
|
|
2558
|
-
startAddr = bank_size
|
|
2559
|
-
endAddr = startAddr + bank_size
|
|
2560
|
-
self.SetBankROM(bank, mbc=mbc, bank_count=bank_count)
|
|
2561
|
-
|
|
2562
|
-
for currAddr in range(startAddr, endAddr, buffer_len):
|
|
2563
|
-
if self.CANCEL:
|
|
2564
|
-
cancel_args = {"action":"ABORT", "abortable":False}
|
|
2565
|
-
cancel_args.update(self.CANCEL_ARGS)
|
|
2566
|
-
self.CANCEL_ARGS = {}
|
|
2567
|
-
self.SetProgress(cancel_args)
|
|
2568
|
-
return
|
|
2569
|
-
|
|
2570
|
-
if currAddr == startAddr:
|
|
2571
|
-
buffer = self.ReadROM(currAddr, buffer_len, True)
|
|
2572
|
-
else:
|
|
2573
|
-
buffer = self.ReadROM(currAddr, buffer_len, False)
|
|
2574
|
-
|
|
2575
|
-
if buffer == False:
|
|
2576
|
-
self.CANCEL = True
|
|
2577
|
-
self.ERROR = True
|
|
2578
|
-
continue
|
|
2579
|
-
|
|
2580
|
-
if not buffer == data_import[pos:pos+buffer_len]:
|
|
2581
|
-
err_pos = 0
|
|
2582
|
-
for i in range(0, buffer_len):
|
|
2583
|
-
if buffer[i] != data_import[pos+i]:
|
|
2584
|
-
err_pos = pos+i
|
|
2585
|
-
break
|
|
2586
|
-
self.SetProgress({"action":"ABORT", "info_type":"msgbox_critical", "info_msg":"The ROM was flashed completely, but verification of written data failed at address 0x{:X}.".format(err_pos), "abortable":False})
|
|
2587
|
-
self.CANCEL = True
|
|
2588
|
-
self.ERROR = True
|
|
2589
|
-
return False
|
|
2590
|
-
|
|
2591
|
-
pos += buffer_len
|
|
2592
|
-
self.SetProgress({"action":"UPDATE_POS", "pos":pos})
|
|
2593
|
-
verified = True
|
|
2594
|
-
|
|
2595
|
-
self.POS = 0
|
|
2596
|
-
if self.MODE == "DMG":
|
|
2597
|
-
self.SetBankROM(0, mbc=mbc, bank_count=bank_count)
|
|
2598
|
-
|
|
2599
|
-
self.SetProgress({"action":"FINISHED", "verified":verified})
|