-
Notifications
You must be signed in to change notification settings - Fork 3
/
SaveGame.sbp
365 lines (300 loc) · 9.77 KB
/
SaveGame.sbp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
'Referenced docs:
' - http://micro-64.com/database/gamesave.shtml
' - https://github.com/sanni/cartreader/blob/master/Cart_Reader/N64.ino
' - https://github.com/DaedalusX64/daedalus/blob/master/Source/Core/FlashMem.cpp
Const CART_SAVE_FLASH_CMD_REG_ADR = &H08010000
Const NUS_SAVE_FLASH_CMD_STATUS = &HE1000000
Const NUS_SAVE_FLASH_CMD_READ = &HF0000000
Sub SaveFlash_Command(cmd As DWord)
NUS_SetAddress(CART_SAVE_FLASH_CMD_REG_ADR)
NUS_writeData(cmd>>16)
NUS_writeData(cmd)
End Sub
Sub SaveFlash_printID()
Dim inbuf[&H220] As Byte, inSize As DWord
SaveFlash_CmdStatusImmdate(inbuf As SAVE_FLASH_STATUS)
Dim FlashType As BytePtr
FlashType = SaveFlash_GetFlashChipLabel(inbuf[7])
printf(ex"Flash Type: %s\n", FlashType)
'
SaveFlash_CmdReadEnable()
NUS_SetAddress(CART_BASEADR_SRAM)
NUS_readRequest(&H20)
NUS_SetAddress(CART_BASEADR_SRAM+&H8000-16)
NUS_readRequest(&H40)
NUS_SetAddress(CART_BASEADR_SRAM+&H8000)
NUS_readRequest(&H40)
FTDI_SendCommand()
FT_Read(hFT, inbuf, &H40, inSize)
printf(ex"\nTop of FlashRAM:\n", NUS_SAVE_FLASH_CMD_STATUS)
Dump(inbuf, &H40, CART_BASEADR_SRAM)
FT_Read(hFT, inbuf, &H80, inSize)
printf(ex"\nTop of FlashRAM:\n", NUS_SAVE_FLASH_CMD_STATUS)
Dump(inbuf, &H80, CART_BASEADR_SRAM)
FT_Read(hFT, inbuf, &H80, inSize)
printf(ex"\nTop of FlashRAM:\n", NUS_SAVE_FLASH_CMD_STATUS)
Dump(inbuf, &H80, CART_BASEADR_SRAM)
End Sub
Sub SaveFlash_CmdReadEnable()
SaveFlash_Command(NUS_SAVE_FLASH_CMD_READ)
End Sub
Sub SaveFlash_CmdStatus()
SaveFlash_Command(NUS_SAVE_FLASH_CMD_STATUS)
NUS_SetAddress(CART_BASEADR_SRAM)
NUS_readRequest(&H4)
SaveFlash_Command(NUS_SAVE_FLASH_CMD_READ)
End Sub
Type SAVE_FLASH_STATUS
data[6] As Byte
chip_id As Byte
End Type
Sub SaveFlash_CmdStatusImmdate(buf As *SAVE_FLASH_STATUS)
SaveFlash_CmdStatus()
Dim inSize As DWord
FTDI_SendCommand()
FT_Read(hFT, buf, &H8, inSize)
printf(ex"FlashRAM command 0x%X results:\n", NUS_SAVE_FLASH_CMD_STATUS)
Dump(buf, &H8, CART_BASEADR_SRAM)
End Sub
Enum NUS_FLASH_CHIP_ID
MX29L1100KC = &H1E
MX29L1101KC = &H1D
MN63F81MPM = &HF1
End Enum
Function SaveFlash_GetFlashChipLabel(id As Byte) As BytePtr
Dim FlashType As BytePtr
Select Case id
Case MX29L1100KC
FlashType = "MX29L1100KC-15B0"
Case MX29L1101KC
FlashType = "MX29L1101KC-15B0" '未確認
Case MN63F81MPM
FlashType = "NUS MN63F81MPM"
Case else
FlashType = "Unknown"
End Select
SaveFlash_GetFlashChipLabel = FlashType
End Function
Function SaveFlash_Detect() As NUS_SAVE_TYPE
Dim status As SAVE_FLASH_STATUS
SaveFlash_CmdStatusImmdate(VarPtr(status))
if GetDWord(status.data) = &H01801111 then
if status.chip_id = MX29L1100KC then
SaveFlash_Detect = NUS_SAVE_FLASH_WORD
else
SaveFlash_Detect = NUS_SAVE_FLASH_BYTE
endif
Dim FlashType As BytePtr
FlashType = SaveFlash_GetFlashChipLabel(status.chip_id)
printf(ex"Save Detect: Flash Type: %s\n", FlashType)
else
SaveFlash_Detect = NUS_SAVE_UNKNOWN
endif
End Function
Const SaveSram_Detect_SloveSize = 128
Const SaveSram_Detect_FFFill_CRC = &H652d544c
Function SaveSram_Detect()(base_addr As DWord, pp_hash As *DWord) As BOOL
if base_addr = 0 then base_addr = CART_BASEADR_SRAM
NUS_SetAddress(base_addr)
NUS_readRequest(SaveSram_Detect_SloveSize>>1)
Dim inbuf[SaveSram_Detect_SloveSize] As Byte, inSize As DWord
FTDI_SendCommand()
FT_Read(hFT, inbuf, SaveSram_Detect_SloveSize, inSize)
Dim hash As DWord
hash = crc32.GetHash(inbuf, NUS_SLOVE_SAMPLE_SIZE1)
if hash <> SaveSram_Detect_FFFill_CRC then
printf(ex"Save Detect: SRAM found. slove hash = %x\n", hash)
' Dump(inbuf, SaveSram_Detect_SloveSize)
SaveSram_Detect = TRUE
else
SaveSram_Detect = FALSE
endif
if pp_hash then SetDWord(pp_hash, hash)
End Function
Const CART_BASEADR_SRAM_2ND = &H08040000
Const CART_BASEADR_SRAM_3RD = &H08080000
Function SaveSramX3_Detect() As BOOL
Dim hash1 As DWord, hash2 As DWord, hash3 As DWord
if SaveSram_Detect(CART_BASEADR_SRAM, VarPtr(hash1)) = FALSE then
SaveSramX3_Detect = FALSE
exitfunction
endif
if SaveSram_Detect(CART_BASEADR_SRAM_2ND, VarPtr(hash2)) = FALSE then
SaveSramX3_Detect = FALSE
exitfunction
endif
if SaveSram_Detect(CART_BASEADR_SRAM_3RD, VarPtr(hash3)) = FALSE then
SaveSramX3_Detect = FALSE
printf(ex"WARNING: SRAMx2 found. this is not surpported.\n")
exitfunction
endif
if (hash1 = hash2) And (hash2 = hash3) then
printf(ex"Save Detect: not SRAMx3 because all bank same data.\n")
SaveSramX3_Detect = FALSE
else
SaveSramX3_Detect = TRUE
endif
End Function
Function SaveEEPROM_Detect() As BOOL
While NUS_InitJoybusAccess(hFT, NUS_JOYBUS_EEPROM)
Dim jret As NUS_JOYBUS_ERR, decbuf[4] As Byte
Dim info As NUS_JoybusDeviceInfo
jret = NUS_JoybusGetDeviceInfo(VarPtr(info))
if jret <> NUS_JOYBUS_OK then ExitWhile
printf(ex"Save Detect: Joybus Device: [%04x]%s status = %02x\t\n", info.id, NUS_JoybusDeviceText(info.id), info.status)
if (info.id = NUS_JB_DEV_ID_EEPROM_4K) or (info.id = NUS_JB_DEV_ID_EEPROM_16K) then
SaveEEPROM_Detect = TRUE
endif
ExitWhile
Wend
NUS_InitRomAccess(hFT)
End Function
Enum NUS_SAVE_TYPE
NUS_SAVE_NONE = 0
NUS_SAVE_SRAM
NUS_SAVE_FLASH_BYTE
NUS_SAVE_FLASH_WORD
NUS_SAVE_EEPROM
NUS_SAVE_SRAMx3 ' for dezaemon
NUS_SAVE_UNKNOWN
_NUS_SAVE_TYPE_NUM
End Enum
Dim NUS_SAVE_TYPE_LABEL[_NUS_SAVE_TYPE_NUM] = [
"NUS_SAVE_NONE",
"NUS_SAVE_SRAM",
"NUS_SAVE_FLASH (Byte)",
"NUS_SAVE_FLASH (Word)",
"NUS_SAVE_EEPROM",
"NUS_SAVE_SRAMx3",
"NUS_SAVE_UNKNOWN"
] As BytePtr
Function SloveSaveType() As NUS_SAVE_TYPE
Dim ret As NUS_SAVE_TYPE
ret = SaveFlash_Detect()
if ret <> NUS_SAVE_UNKNOWN then
SloveSaveType = ret
else
if SaveSramX3_Detect() then
SloveSaveType = NUS_SAVE_SRAMx3
else if SaveSram_Detect() then
SloveSaveType = NUS_SAVE_SRAM
else if SaveEEPROM_Detect() then
SloveSaveType = NUS_SAVE_EEPROM
else
'現時点でEEPROMかセーブなしか判定できないのでUnknownを返す
SloveSaveType = NUS_SAVE_UNKNOWN
endif
endif
End Function
Function GetSaveTypeLabel(stype As NUS_SAVE_TYPE) As BytePtr
if stype >= _NUS_SAVE_TYPE_NUM then stype = NUS_SAVE_UNKNOWN
GetSaveTypeLabel = NUS_SAVE_TYPE_LABEL[stype As DWord]
End Function
Function DumpSramFile(fileName As BytePtr, SramSize As DWord, SaveType As NUS_SAVE_TYPE)(BaseAddress As DWord) As Long
Dim ret = TRUE As Long
Dim out As File
if out.openFile(fileName, GENERIC_WRITE) = FALSE then
Print "Failed to create file."
ExitFunction
endif
Dim buffer As BytePtr
buffer = calloc(SramSize)
if SaveType = NUS_SAVE_SRAMx3 then
ret = DumpSram(buffer + SramSize/3*0, SramSize/3, NUS_SAVE_SRAM, CART_BASEADR_SRAM)
ret = DumpSram(buffer + SramSize/3*1, SramSize/3, NUS_SAVE_SRAM, CART_BASEADR_SRAM_2ND)
ret = DumpSram(buffer + SramSize/3*2, SramSize/3, NUS_SAVE_SRAM, CART_BASEADR_SRAM_3RD)
else
ret = DumpSram(buffer, SramSize, SaveType, BaseAddress)
endif
out.write(buffer, SramSize)
free(buffer)
out.close()
DumpSramFile = ret
End Function
Function DumpSram(buffer As BytePtr, SramSize As DWord, SaveType As NUS_SAVE_TYPE)(BaseAddress As DWord) As Long
Dim inSize As DWord
Dim readOffset = &H0 As DWord
Dim IsWordAddressing As BOOL
if BaseAddress = 0 then
BaseAddress = CART_BASEADR_SRAM
endif
Const BufferSize = 128 ' bytes
if SaveType = NUS_SAVE_FLASH_WORD then
IsWordAddressing = TRUE
else
IsWordAddressing = FALSE
endif
flush()
N64PowerON()
NUS_SetAddress(BaseAddress)
if FTDI_SendCommand() <> FT_OK then Goto *DFR_EXIT
Print "dumping data..."
Dim time As DWord, lt As DWord, retry As DWord
time = GetTickCount()
Do
if readOffset >= SramSize then ExitDo
if IsWordAddressing then
NUS_SetAddress(BaseAddress + (readOffset>>1))
else
NUS_SetAddress(BaseAddress + readOffset)
endif
NUS_readRequest(BufferSize>>1)
if FTDI_SendCommand() <> FT_OK then Goto *DFR_EXIT
if FT_Read(hFT, buffer + readOffset, BufferSize, inSize) <> FT_OK then Goto *DFR_EXIT
if inSize <> BufferSize then
printf(ex"receive size error.\n")
retry++
if retry>5 then Goto *DFR_EXIT
Continue
endif
readOffset+ = BufferSize
if readOffset Mod (&H500*2) = 0 then
ConsoleReturnLine()
printf(ex"Address = %08X ... %d%% [%dKB/s] ", readOffset, (readOffset/SramSize)*100, readOffset/(GetTickCount()-time))
if GetKeyState(VK_ESCAPE) And &H80 then Print ex"\n[ESC]Cancelled by user.":Goto *DFR_EXIT
endif
Loop
lt = GetTickCount()-time
printf(ex"\nDump Successfull !\nTime:%dms = %ds = %dmin\n", lt, lt/1000, lt/1000/60)
DumpSram = TRUE
*DFR_EXIT
N64PowerOFF()
End Function
Function DumpEEPROM_File(fileName As BytePtr) As Long
Dim jret As NUS_JOYBUS_ERR
Dim info As NUS_JoybusDeviceInfo
Dim eepbuf[8] As Byte, block As Long, i As Long
Print
While NUS_InitJoybusAccess(hFT, NUS_JOYBUS_EEPROM)
jret = NUS_JoybusGetDeviceInfo(VarPtr(info))
if jret <> NUS_JOYBUS_OK then
printf(ex"Joybus error: %s\n", NUS_JoybusErrorText(jret))
ExitWhile
endif
if info.id = NUS_JB_DEV_ID_EEPROM_4K then
block = 4*1024/8/8
else if info.id = NUS_JB_DEV_ID_EEPROM_16K then
block = 16*1024/8/8
else
printf(ex"Dump save error: Unknown EEPROM type.\n")
ExitWhile
endif
Dim eepsave As File
eepsave.openFile(fileName, GENERIC_WRITE)
for i = 0 To block-1
printf(ex"Reading EEPROM block %d/%d\r", i, block-1)
jret = NUS_JoybusReadEEPROM(eepbuf, i)
if jret <> NUS_JOYBUS_OK then
printf(ex"Joybus error: %s\n", NUS_JoybusErrorText(jret))
ExitWhile
endif
' Dump(eepbuf, 8, i*8)
eepsave.write(eepbuf, 8)
Next i
eepsave.close()
DumpEEPROM_File = TRUE
ExitWhile
Wend
NUS_InitRomAccess(hFT)
Print
End Function