-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGB_SoftwareLevel.sbp
952 lines (780 loc) · 24.4 KB
/
GB_SoftwareLevel.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
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
'-----------------
' Software Level
'-----------------
Const DMG_HEADER_ADDRESS = &H0100
Const DMG_ADDRESS_BANK0 = &H0000
Const DMG_ADDRESS_BANKn = &H4000
const DMG_BANK_SIZE = 16*1024
Const MBC_ADR_ROM_BANK_NUMBER = &H2000
Const MBC_ADR_ROM_BANK_NUMBER_HIBYTE = &H3000
Type Align(1) DMG_ROM_HEADER
EntryPoint AS DWord '0100h
NLogo[47] AS Byte '0104h
Title[15] AS Byte '0134h
' GBCFlag AS Byte '0143h
MakerCode AS Word '0144h
SGBFlag AS Byte '146
CartType AS Byte
RomSize AS Byte
SramSize AS Byte
RegionCode AS Byte
MakerCode_old AS Byte
RomVersion AS Byte
HeaderComplement As Byte
CheckSum AS Word
End Type
'Headerをわかりやすくした奴
Type DMG_ROM_INFO
raw AS DMG_ROM_HEADER
bLogoCheck AS BOOL
Title[16] AS Byte
GameCode[4] AS Byte '文字列扱い(Null終端)
ConsoleCode[4] AS Byte ' DMG or CGB 文字列扱い(Null終端)
ConsoleFlag AS Long
MBCType AS DMG_MBC_TYPE
RomSize AS DWord
SramSize AS DWord
RomVersion As DWord
Region As DMG_COUNTRY
hasGameCode As Byte
special AS Long
isNeedDeepRead AS BOOL
End Type
Const DMG_NLOGO_SUM = &H1546
Enum DMG_CONSOLE_FLAG
DMG_CF_NGB = &H01
DMG_CF_SGB = &H02
DMG_CF_GBC = &H04
End Enum
Enum DMG_MBC_TYPE
DMG_NO_MBC = 0
DMG_MBC1
DMG_MBC2
DMG_MBC3
DMG_MBC4
DMG_MBC5
DMG_MBC6
DMG_MBC7
DMG_MMM01
DMG_POCKET_CAMERA
DMG_TAMA5
DMG_HuC3
DMG_HuC1
DMG_GMMC1
DMG_MBC_TYPE_MAX
DMG_MBC_TYPE_UNKNOWN
End Enum
Dim DMG_MBC_TYPE_STR[DMG_MBC_TYPE_MAX+1] = [
"DMG_NO_MBC",
"DMG_MBC1",
"DMG_MBC2",
"DMG_MBC3",
"DMG_MBC4",
"DMG_MBC5",
"DMG_MBC6",
"DMG_MBC7",
"DMG_MMM01",
"DMG_POCKET_CAMERA",
"DMG_TAMA5",
"DMG_HuC3",
"DMG_HuC1",
"DMG_G-MMC1(MX15002)",
"MBC BUG",
"MBC Unknown"
] AS BytePtr
Enum SPECIAL_MODE
SPECIAL_DISABLE_CHECKSUM = 1
End Enum
Enum DMG_COUNTRY
DMG_COUNTRY_JAPAN = 0
DMG_COUNTRY_USA
DMG_COUNTRY_EUROPE
DMG_COUNTRY_INTERNATIONAL
DMG_COUNTRY__NUM
DMG_COUNTRY_UNKNOWN
End Enum
' ↑のラベル
Dim DMG_COUNTRY_LABEL[DMG_COUNTRY__NUM*2+2] = [
"J", "Japan" ,
"E", "USA" ,
"P", "Europe" ,
"I", "World" ,
"?", "Unknown"
] AS BytePtr
Const MBC_ADR_SRAM_BANK_NUMBER = &H4000
Const MBC_ADR_SRAM_ENABLE = &H0000
Const MBC1_ADR_MODE_SELECT = &H6000
'-------------------------
' Top Level Functions
'-------------------------
Function DumpFullRomToFile(fe AS *FT232H_DMGROM,filename AS BytePtr,ByRef info AS DMG_ROM_INFO) AS BOOL
Dim buf AS BytePtr,lt As DWord, retry AS DWord
drop_count=0
*DFRTF_DUMP_START
lt=GetTickCount()
buf=RomDumpFull(fe,VarPtr(info))
lt=GetTickCount() - lt
printf(ex"¥nProcess Time : %dms %ds¥n",lt,lt/1000)
Dim actualSum As DWord
actualSum = DMG_CalcSum(buf,info.RomSize)
printf(ex"Checksum: ¥n [Header] 0x%04X¥n [Actual] 0x%04X ... ",info.raw.CheckSum, actualSum)
if actualSum = info.raw.CheckSum Then
colorPrint(PH_SUCCESS, ex"[ OK ]¥n")
Else
colorPrint(PH_ERROR, ex"[ NG ]¥n")
if info.isNeedDeepRead And (retry<>2) Then
printf(ex"NP RETRY...¥n¥n")
retry++
Goto *DFRTF_DUMP_START
End If
End If
Dim fout AS File
if fout.openFile(filename,GENERIC_WRITE)=TRUE Then
fout.write(buf,info.RomSize)
fout.close()
Else
printf(EX"File Write Error! path:¥q%s¥q GLE=%d¥n", filename,GetLastError())
End If
free(buf): buf=NULL
End Function
Function DumpSramToFile(fe AS *FT232H_DMGROM,filename AS BytePtr,ByRef info AS DMG_ROM_INFO) AS BOOL
Dim fout AS File
if fout.openFile(filename,GENERIC_WRITE)=FALSE Then
printf(ex"File open error : %s¥n",filename)
exitfunction
End If
Dim buf AS BytePtr
buf=SramDumpFull(fe,VarPtr(info))
if info.MBCType=DMG_MBC2 Then
info.SramSize=512
End If
fout.write(buf,info.SramSize)
fout.close()
Dump(buf, 16*6)
free(buf): buf=NULL
DumpSramToFile=TRUE
End Function
Sub VerifyData(src As BytePtr, verify As BytePtr, size AS DWord)
Dim i As DWord
Dim err As DWord
Dim err_start As DWord, err_end AS DWord
for i=0 to size-1
if src[i] <> verify[i] then
err++
if err_start=0 then
err_start=i
Dim dispAdr As Long
dispAdr = (i And &HFFFFFFF0) -16
if dispAdr < 0 then dispAdr = 0
Dump(src + dispAdr, 48, dispAdr)
Dump(verify + dispAdr, 48, dispAdr)
endif
err_end = i
End If
Next
if err = 0 then
Print "Verify ... OK"
Else
Dim err_rate As DWord
err_rate = (err*10000)/size
printf(ex"Verify ... NG.¥n - Error range: %04xh-%04xh¥n - Error rate : %d/%d ::: %d.%02d%%¥n",_
err_start, err_end, err, size, err_rate/100, err_rate Mod 100)
End If
End Sub
Function WriteSramFromFile(fe AS *FT232H_DMGROM,filename AS BytePtr,ByRef info AS DMG_ROM_INFO) AS BOOL
Dim buf AS BytePtr
Dim fout AS File
if fout.openFile(filename,GENERIC_READ)=FALSE Then
printf(ex"File open error : %s¥n",filename)
exitfunction
End If
Dim size AS DWord
size = info.SramSize
if info.SramSize < DMG_SRAM_BANK_SIZE Then
size = DMG_SRAM_BANK_SIZE
End If
buf=calloc(size)
fout.read(buf,info.SramSize)
fout.close()
SramWrite(fe,buf,VarPtr(info))
Dim verify As BytePtr
verify=SramDumpFull(fe,VarPtr(info))
VerifyData(buf, verify, size)
free(buf): buf=NULL
free(verify): verify=NULL
End Function
'-------------------------
' High Level Functions
'-------------------------
Function GetDumpAddress(info AS *DMG_ROM_INFO, bank As DWord) As DWord
if info->MBCType <> DMG_MMM01 Then
GetDumpAddress=DMG_ADDRESS_BANKn
Else
' MMM01
if bank And &H1F then
GetDumpAddress=DMG_ADDRESS_BANKn
Else
GetDumpAddress=DMG_ADDRESS_BANK0
End If
printf(ex"[MMM01] bnk=%02x addr=%04x¥n", bank, GetDumpAddress)
End If
End Function
Function RomDumpFull(fe As *FT232H_DMGROM,info AS *DMG_ROM_INFO) As BytePtr
Dim flags=0 AS DWord
if info->MBCType= DMG_GMMC1 or info->isNeedDeepRead Then
flags OR= DMG_ACCESS_RD_PULSE OR DMG_ACCESS_DEEP_READ
printf(ex"[GBMC] RD-Palse and Deep-Read Enabled¥n")
endif
if info->MBCType=DMG_MMM01 Then
MMM01_Init_RomMode(fe)
End If
if info->MBCType=DMG_TAMA5 Then
flags OR= DMG_ACCESS_NO_CS_PULSE
End If
Dim buf AS BytePtr
buf = calloc(info->RomSize)
DMG_ReadCart(fe,buf,DMG_ADDRESS_BANK0,DMG_BANK_SIZE, flags)
printf(ex"¥n")
dim i AS Long,bankCount As Long,lt AS DWord
bankCount=info->RomSize / DMG_BANK_SIZE -1
lt=GetTickCount()
For i=1 To bankCount
printf(ex"[DumpROM] Bank:%02X/%02X %d%% ::: %dkb/s ¥r",i,bankCount,i/bankCount*100, ((i*DMG_BANK_SIZE)/(GetTickCount()-lt)) As DWord)
MBC_RomBankSet(fe,info->MBCType,i)
DMG_ReadCart(fe,buf + i*DMG_BANK_SIZE,GetDumpAddress(info, i),DMG_BANK_SIZE,flags)
if flags And DMG_ACCESS_DEEP_READ then
printf(ex"bank=%d ¥n",i)
Dump(buf + i*DMG_BANK_SIZE,16,i*DMG_BANK_SIZE)
endif
if CheckCancel() Then ExitFor
Next
RomDumpFull=buf
printf(ex"¥n")
End Function
Const DMG_SRAM_BANK_SIZE = &H2000
Const DMG_SRAM_ADDRESS = &HA000
Function SramDumpFull(fe As *FT232H_DMGROM,info AS *DMG_ROM_INFO) As BytePtr
Dim buf AS BytePtr
if info->SramSize > DMG_SRAM_BANK_SIZE Then
buf = calloc(info->SramSize)
Else
buf = calloc(DMG_SRAM_BANK_SIZE)
End If
MBC_RamEnable(fe,info->MBCType,TRUE)
printf(ex"¥n")
dim i AS Long,bankCount As Long
bankCount=Abs(info->SramSize / DMG_SRAM_BANK_SIZE-1)
For i=0 To bankCount
printf(ex"[DumpSRAM] Bank:%02X/%02X %d%% ¥r",i,bankCount,i/bankCount*100)
MBC_SramBankSet(fe,info->MBCType,i)
DMG_ReadCart(fe,buf + i*DMG_SRAM_BANK_SIZE,DMG_SRAM_ADDRESS,DMG_SRAM_BANK_SIZE,DMG_ACCESS_RD_PULSE)
if CheckCancel() Then ExitFor
Next
MBC_RamEnable(fe,info->MBCType,FALSE)
if info->MBCType=DMG_MBC2 Then
' DMG_MBC2_SRAM_4to8(buf)
End If
SramDumpFull=buf
printf(ex"¥n")
End Function
Function SramWrite(fe As *FT232H_DMGROM, buf AS BytePtr,info AS *DMG_ROM_INFO)
MBC_RamEnable(fe,info->MBCType,TRUE)
printf(ex"¥n")
dim i AS Long,bankCount As Long
bankCount=Abs(info->SramSize / DMG_SRAM_BANK_SIZE-1)
For i=0 To bankCount
printf(ex"[WriteSRAM] Bank:%02X/%02X %d%% ¥r",i,bankCount,i/bankCount*100)
MBC_SramBankSet(fe,info->MBCType,i)
DMG_WriteCart(fe,buf + i*DMG_SRAM_BANK_SIZE,DMG_SRAM_ADDRESS,DMG_SRAM_BANK_SIZE)
if CheckCancel() Then ExitFor
Next
MBC_RamEnable(fe,info->MBCType,FALSE)
printf(ex"¥n")
End Function
'-----------------------------
' Memory Bank Controller util
'-----------------------------
'4000h-7FFFhのROMバンクをセットする
Sub MBC_RomBankSet(fe As *FT232H_DMGROM, mbc AS Long, bankNum AS Long)
' fe->ROMEnable(TRUE)
if mbc=DMG_MBC2 or mbc=DMG_GMMC1 Then
MBC_RegisterWrite(fe, &H2100, bankNum)
Elseif mbc=DMG_MMM01 Then
MMM01_SwitchRomBank(fe, bankNum)
elseif mbc=DMG_TAMA5 then
TAMA5_SwitchRomBank(fe, bankNum)
Else
MBC_RegisterWrite(fe, MBC_ADR_ROM_BANK_NUMBER, bankNum)
End If
' printf("[MBC][%x]",bankNum And &HFF)
if (mbc >= DMG_MBC5) And (mbc <= DMG_MBC7) Then
MBC_RegisterWrite(fe, MBC_ADR_ROM_BANK_NUMBER_HIBYTE, (bankNum>>8))
' printf("[MBC5 HIBYTE SET][%x]",bankNum>>8)
Endif
' fe->ROMEnable(FALSE)
End Sub
'A000h-BFFFhのSRAMバンクをセットする
Sub MBC_SramBankSet(fe As *FT232H_DMGROM, mbc AS Long, bankNum AS Long)
if mbc<>DMG_MBC2 Then
MBC_RegisterWrite(fe, MBC_ADR_SRAM_BANK_NUMBER, bankNum)
End If
printf("[MBC][SRAM][%x]",bankNum And &HFF)
End Sub
Sub MBC_RamEnable(fe As *FT232H_DMGROM, mbc AS Long, ef AS BOOL)
if mbc=DMG_MBC1 or mbc=DMG_HuC1 Then
if ef Then
MBC_RegisterWrite(fe, MBC1_ADR_MODE_SELECT, &H01)'RAM Banking Mode
printf("[MBC1][SRAM_BANKING_MODE]")
Else
MBC_RegisterWrite(fe, MBC1_ADR_MODE_SELECT, &H00)'ROM Banking Mode
printf("[MBC1][ROM_BANKING_MODE]")
End If
End If
if ef Then
MBC_RegisterWrite(fe, MBC_ADR_SRAM_ENABLE, &H0A) 'read/write Enable
Else
MBC_RegisterWrite(fe, MBC_ADR_SRAM_ENABLE, &H00) 'read/write Enable
End If
End Sub
Const MBC2_SRAM_SIZE = 512
Sub DMG_MBC2_SRAM_4to8(buf AS BytePtr)
Dim tmp AS BytePtr
tmp=calloc(MBC2_SRAM_SIZE)
memcpy(tmp,buf,MBC2_SRAM_SIZE)
dim i AS Long
For i=0 To MBC2_SRAM_SIZE/2
buf[i] = (tmp[i*2] And &H0F) or ((tmp[i+2] And &H0F)<<4 )
Next i
End Sub
'参考
'https://github.com/n13i/writeboy/blob/master/WriteBoy/cart_type.ino
'https://forums.nesdev.com/viewtopic.php?f=12&t=11453&start=147
Function GBMC_MapEntire(fe AS *FT232H_DMGROM) AS BOOL
'G-MMC Opreation Mode
GBMC_RegisterWrite(fe, &H0120, &H09)
GBMC_RegisterWrite(fe, &H0121, &Haa)
GBMC_RegisterWrite(fe, &H0122, &H55)
GBMC_RegisterWrite(fe, &H013f, &Ha5)
'05h = Map "MENU PROGRAM", 04h = カセット全体をマップ
GBMC_RegisterWrite(fe, &H0120, &H04)
GBMC_RegisterWrite(fe, &H013f, &Ha5)
/*
GBMC_RegisterWrite(fe, &H0120, &H10)
GBMC_RegisterWrite(fe, &H013f, &Ha5)
*/
'0xA5
if FT232H_ReadByte(fe,&H013f) = &HA5 Then
GBMC_MapEntire=TRUE
Else
GBMC_MapEntire=FALSE
End If
'G-MMC Operation Mode End
GBMC_RegisterWrite(fe, &H0120, &H08)
GBMC_RegisterWrite(fe, &H013f, &Ha5)
End Function
Sub MMM01_Init_RomMode(fe As *FT232H_DMGROM)
/* Configuration
* RomBankLow = RomBankLow(2000h:4..0)
* RomBankMid = RamBankLow(4000h:1..0)
* RomBankHigh= not used (0 fixed)
* RamBanking = Enable
* RamBankLow = fixed bank 0 ( only 8KB, RomBankMidはMap中は変えられない )
* Ram32KBが現れたら別モードを作る必要がある
* Ram128KB,Rom4MBが現れたらRSTを制御する仕組みを作るか、カートリッジを抜き差ししてもらう
*/
' ROM Bank Register
MBC_RegisterWrite(fe, &H2000, 0) ' start bank
' RAM Bank Register
' RamBankLow=0, RamBankHigh=0, RomBankHigh=0, MBC1ModeWR=Enable(bit6)
MBC_RegisterWrite(fe, &H4000, &H00)
' Mode Register
' Multiplex mode enable(40h), not rom mask, RAM Banking Enable(1h)
MBC_RegisterWrite(fe, &H6000, &H41)
' RAM Enable Register
' RAM Disable, no ram mask, mapping enable(40h)
' MBC_RegisterWrite(fe, &H0000, &H00)' 3A,7A
MBC_RegisterWrite(fe, &H0000, &H40)' 3A,7A
End Sub
Sub MMM01_SwitchRomBank(fe As *FT232H_DMGROM, bank AS DWord)
MBC_RegisterWrite(fe, &H2000, bank And &H1F) ' RomBankLow 5bit
MBC_RegisterWrite(fe, &H4000, &H40 OR (bank>>5) And &H3) ' RomBankHigh 2bit(RamBankLow)
if bank>>6 then
printf(ex"[Warning][MMM01] MMM01 RomBankHighBanking is not surpported.¥n")
End If
printf(ex"[MMM01] bank=%x, RomBankLow=%x RomBankMid=%x¥n",bank,bank And &H1F, (bank>>5) And &H3)
End Sub
Sub TAMA5_WaitRegister(fe AS *FT232H_DMGROM)
Dim buf[15] As Byte, i as Long
for i = 0 to 100
FT232H_ReadEPROM(fe,buf,&HA000,16,TRUE)
Dump(buf,16,&HA000)
if (buf[0] And &H3) = 1 then ExitSub
Next
Print "TAMA5 replay timeout."
End Sub
Sub TAMA5_Init(fe As *FT232H_DMGROM)
fe->ROMEnable(TRUE)
MBC_RegisterWrite(fe, &HA001, &H0A) 'TAMA5 unlock
TAMA5_WaitRegister(fe)
fe->ROMEnable(FALSE)
End Sub
Sub TAMA5_SwitchRomBank(fe As *FT232H_DMGROM, bank AS DWord)
if bank=0 then TAMA5_Init(fe)
fe->ROMEnable(TRUE)
' MBC_RegisterWrite(fe, &HA001, &H0A) 'TAMA5 unlock
' TAMA5_WaitRegister(fe)
MBC_RegisterWrite(fe, &HA001, &H00) 'ROM BANK LOW
MBC_RegisterWrite(fe, &HA000, bank And &HF) ' DATA
MBC_RegisterWrite(fe, &HA001, &H01) 'ROM BANK HIGH
MBC_RegisterWrite(fe, &HA000, bank >> 4) ' DATA
fe->ROMEnable(FALSE)
End Sub
Sub TAMA5_SetSramAddress(fe As *FT232H_DMGROM, address AS DWord)
MBC_RegisterWrite(fe, &HA001, &H06) 'CMD=SAVE ADDRESS LOW
MBC_RegisterWrite(fe, &HA000, address And &HF) '
MBC_RegisterWrite(fe, &HA001, &H07) 'CMD=SAVE ADDRESS LOW
MBC_RegisterWrite(fe, &HA000, address >> 4) ' DATA
End Sub
Function TAMA5_ReadSramByte(fe As *FT232H_DMGROM) AS Byte
Dim u As Byte, l As Byte
MBC_RegisterWrite(fe, &HA001, &H0D)
u = FT232H_ReadByte(fe, &HA000) And &HF
MBC_RegisterWrite(fe, &HA001, &H0C)
l = FT232H_ReadByte(fe, &HA000) And &HF
TAMA5_ReadSramByte = (u << 4) OR l
End Function
Function TAMA5_WriteSramByte(fe As *FT232H_DMGROM, data As Byte) AS Byte
MBC_RegisterWrite(fe, &HA001, &H04)
MBC_RegisterWrite(fe, &HA000, data And &HF)
MBC_RegisterWrite(fe, &HA001, &H05)
MBC_RegisterWrite(fe, &HA000, data>>4)
End Function
Function TAMA5_ReadSramByteWithAddress(fe As *FT232H_DMGROM, addr AS DWord) AS Byte
fe->ROMEnable(TRUE)
TAMA5_SetSramAddress(fe,addr)
TAMA5_WaitRegister(fe)
TAMA5_ReadSramByteWithAddress = TAMA5_ReadSramByte(fe)
fe->ROMEnable(FALSE)
End Function
Function TAMA5_WriteSramByteWithAddress(fe As *FT232H_DMGROM, addr AS DWord, data AS Byte) AS Byte
fe->ROMEnable(TRUE)
TAMA5_WriteSramByte(fe,data)
TAMA5_WaitRegister(fe)
TAMA5_SetSramAddress(fe,addr)
fe->ROMEnable(FALSE)
End Function
'-----------------------
' ROM HEADER UTILs
'-----------------------
Function DMG_GetCountryString(country_code AS Byte) As BytePtr
if country_code >= DMG_COUNTRY__NUM Then country_code = DMG_COUNTRY__NUM
DMG_GetCountryString = DMG_COUNTRY_LABEL[country_code*2+1]
End Function
Function DMG_GetCountryCodeString(country_code AS Byte) As BytePtr
if country_code >= DMG_COUNTRY__NUM Then country_code = DMG_COUNTRY__NUM
DMG_GetCountryCodeString = DMG_COUNTRY_LABEL[country_code*2]
End Function
Function DMG_GetRegionId(letter As Byte) As DMG_COUNTRY
Dim i As Long
DMG_GetRegionId = DMG_COUNTRY_UNKNOWN
for i = 0 to DMG_COUNTRY__NUM
if letter = DMG_COUNTRY_LABEL[i*2][0] then
SetDWord(VarPtr(DMG_GetRegionId), i)
exitfor
endif
Next
End Function
Function DMG_SloveRegion(ByRef info As DMG_ROM_INFO) As DMG_COUNTRY
Dim ret = DMG_COUNTRY__NUM As DMG_COUNTRY
if info.hasGameCode Then
ret = DMG_GetRegionId(info.GameCode[3])
Else
if info.raw.RegionCode = 0 Then
ret = DMG_COUNTRY_JAPAN
else
ret = DMG_COUNTRY_INTERNATIONAL
endif
endif
DMG_SloveRegion = ret
End Function
Function isFill(buf AS BytePtr, size AS DWord, c AS Byte) AS BOOL
dim i as Long
for i=0 to size-1
if buf[i] <> c then
exitfunction
End If
Next
isFill = TRUE
End Function
'GBのROMヘッダ取得
Sub DMG_GetHeader(fe As *FT232H_DMGROM,header AS *DMG_ROM_HEADER)
DMG_ReadCart(fe,header,DMG_HEADER_ADDRESS,sizeof(DMG_ROM_HEADER), DMG_ACCESS_RD_PULSE)
if isFill(header, sizeof(DMG_ROM_HEADER), &HFF) then
' printf(ex"FF fill detected¥n")
DMG_ReadCart(fe,header,DMG_HEADER_ADDRESS,sizeof(DMG_ROM_HEADER), DMG_ACCESS_RD_PULSE OR DMG_ACCESS_NO_CS_PULSE)
End If
End Sub
Function IsGameCodeLetter(letter AS Byte) As BOOL
IsGameCodeLetter=TRUE
if (letter < GetByte("A")) OR (letter > GetByte("Z")) then
if (letter < GetByte("0")) OR (letter > GetByte("9")) then
IsGameCodeLetter = FALSE
endif
End If
End Function
Function IsExtendedGameIdLetter(code AS *Byte) As BOOL
' A: 4桁拡張ゲームIDのバンクA
' B: 4桁拡張ゲームIDのバンクB
' C: 無いと思われる
' V: 振動カートリッジ
' H: ポケットファミリー2 (ハドソン製造ということ?)
' K: コロコロカービィ
' P: ポケットカメラ
' M: GBメモリ
Dim extended_sign="ABVHKP" As BytePtr
Dim i=0 AS Long
Do
if extended_sign[i] = code[0] Then
IsExtendedGameIdLetter=TRUE
ExitFunction
elseif extended_sign[i] = 0 Then
ExitDo
End If
i++
Loop
IsExtendedGameIdLetter=FALSE
End Function
'生のheaderからinfoを作成
Sub DMG_rawHeaderToInfo(ByRef rawHeader AS DMG_ROM_HEADER,ByRef info As DMG_ROM_INFO)
memcpy(VarPtr(info),VarPtr(rawHeader),sizeof(DMG_ROM_HEADER))
Dim i AS Long,sum AS DWord
For i=0 To 47
sum+=rawHeader.NLogo[i]
Next
if sum=DMG_NLOGO_SUM Then
info.bLogoCheck=TRUE
Else
info.bLogoCheck=FALSE
End If
info.hasGameCode = FALSE
memcpy(info.Title,rawHeader.Title,16)
info.Title[16]=0
If rawHeader.Title[15] = &HC0 Then
info.ConsoleFlag = DMG_CF_GBC 'GBC専用
info.hasGameCode = TRUE
Else
info.ConsoleFlag = DMG_CF_NGB
if rawHeader.Title[15] AND &H80 Then
info.ConsoleFlag = info.ConsoleFlag Or DMG_CF_GBC
info.hasGameCode = TRUE
End If
if rawHeader.SGBFlag <> &H00 Then
info.ConsoleFlag = info.ConsoleFlag Or DMG_CF_SGB
End If
Endif
'タイトルが16文字より少ない場合、ゲームIDがタイトルの後ろの方に書かれていることがある。
/* if info.Title[10]=&H00 or info.Title[10]=&H20 Then
info.hasGameCode = TRUE
End If*/
if IsExtendedGameIdLetter(VarPtr(info.Title[11])) Then
if DMG_GetRegionId(info.Title[11+3]) <> DMG_COUNTRY_UNKNOWN Then
if (IsGameCodeLetter(info.Title[11+1]) OR IsGameCodeLetter(info.Title[11+2])) = 0 then
info.hasGameCode = FALSE
End If
Else
info.hasGameCode = FALSE
End If
Else
if win_strncmp(info.Title+11, "MENU", 4) = FALSE then
info.hasGameCode = FALSE
End If
End If
/* for i=0 to 3
Dim cbyte As Byte
cbyte = info.Title[11+i]
if (cbyte < GetByte("A")) OR (cbyte > GetByte("Z")) then
if (cbyte < GetByte("0")) OR (cbyte > GetByte("9")) then
info.hasGameCode = FALSE
exitfor
endif
End If
Next
*/
' 11byte目以降IDあり:カラー系ゲーム
' 11byte目以降はあるがIDなし:ポヨンのダンジョンルーム
'これでもすり抜けるようなら、GameID末尾の国コードJ E P Uなどを頼る
if info.hasGameCode then
memcpy(info.GameCode,VarPtr(info.Title[11]),4)
info.GameCode[4] = 0
info.Title[11] = 0
if info.ConsoleFlag = DMG_CF_GBC then
lstrcpy(info.ConsoleCode, "CGB") ' Color Only
Else
lstrcpy(info.ConsoleCode, "DMG")
End If
End If
Dim ct AS Byte, mt AS DMG_MBC_TYPE
ct=rawHeader.CartType
if ct=0 or ct=8 or ct=09 Then
mt=DMG_NO_MBC
Elseif ct >= &H01 And ct<=&H03 Then
mt=DMG_MBC1
Elseif ct >= &H05 And ct<=&H06 Then
mt=DMG_MBC2
Elseif ct >= &H0B And ct<=&H0D Then
mt=DMG_MMM01
Elseif ct >= &H0F And ct<=&H013 Then
mt=DMG_MBC3
Elseif ct >= &H19 And ct<=&H1E Then
mt=DMG_MBC5
Elseif ct = &H20 Then
mt=DMG_MBC6
Elseif ct = &H22 Then
mt=DMG_MBC7
Elseif ct = &HFC Then
mt=DMG_POCKET_CAMERA
Elseif ct = &HFD Then
mt=DMG_TAMA5
Elseif ct = &HFE Then
mt=DMG_HuC3
Elseif ct = &HFF Then
mt=DMG_HuC1
Else
mt=DMG_MBC_TYPE_UNKNOWN
End If
if lstrcmp(info.GameCode,"MENU") = 0 Then
mt=DMG_GMMC1
End If
info.MBCType=mt
' printf(ex"%02X ::: %s¥n",ct,DMG_MBC_TYPE_STR[mt])
'54h ::: (50h --> 8Mbit) + (04h --> 4Mbit) = 12Mbit = 1.5MB
info.RomSize = (&H8000 << (rawHeader.RomSize And &H0F))
if (info.RomSize And &HF0) <> 0 Then
info.RomSize += &H8000 << ((rawHeader.RomSize>>4) And &H0F)
End If
Const DMG_SRAM_SIZE_TABLE_MAX = 5
Dim DMG_SRAM_SIZE_TABLE[DMG_SRAM_SIZE_TABLE_MAX] = [
&H00000, '00h 0KB
&H00800, '01h 2KB
&H02000, '02h 8KB
&H08000, '03h 32KB
&H20000, '04h 128KB
&H10000 '05h 64KB 'なんでやねん
] AS Long
if info.MBCType = DMG_MBC2 Then
info.SramSize=&H2*1024
Else
info.SramSize = DMG_SRAM_SIZE_TABLE[rawHeader.SramSize Mod (DMG_SRAM_SIZE_TABLE_MAX+1)]
End If
info.RomVersion = rawHeader.RomVersion
if rawHeader.RomVersion >= &H30 Then
info.RomVersion = info.RomVersion - &H30
End If
info.RomVersion = info.RomVersion + 10 '0を1.0扱いする
Dim title_len As Long
title_len = lstrlen(info.Title)
for i=title_len To 0 Step -1
' printf(ex"'%s'¥n",info.Title)
if (info.Title[i] < GetByte("0")) or (info.Title[i] > &H7f) then
info.Title[i] = 0
Else
exitfor
End If
Next
info.isNeedDeepRead=FALSE
info.Region = DMG_SloveRegion(info)
End Sub
Function DMG_GenerateInfoText(ByRef info AS DMG_ROM_INFO) AS BytePtr
Dim str AS StringClass
str.allocStr(1024)
str.cpy(ex"DMG ROM Infomation:¥n")
str.sprintf(ex" Title : %s¥n", info.Title)
if info.hasGameCode Then str.sprintf(ex" GameID : %s-%s¥n",info.ConsoleCode,info.GameCode)
str.sprintf(ex" MBC : %s [%02Xh]¥n RomSize : %d KB¥n SramSize : %d KB¥n Region : %s¥n Version : %d.%d¥n CheckSum : %04X¥n Console : ", _
DMG_MBC_TYPE_STR[info.MBCType],info.raw.CartType, _
info.RomSize/1024, _
info.SramSize/1024, _
DMG_GetCountryString(info.Region), _
info.RomVersion/10, info.RomVersion Mod 10, _
info.raw.CheckSum _
)
if info.ConsoleFlag = DMG_CF_GBC Then
str.cat("GBC only ")
Else
if info.ConsoleFlag And DMG_CF_NGB Then str.cat("NGB ")
if info.ConsoleFlag And DMG_CF_SGB Then str.cat("SGB ")
if info.ConsoleFlag And DMG_CF_GBC Then str.cat("GBC ")
Endif
str.cat(ex"¥n Contact : ")
if info.bLogoCheck=FALSE then
str.cat(ex"接触不良 [Contact Failue]¥n")
Else
str.cat(ex"OK¥n")
End If
#ifdef _DEBUG
str.cat(MakeFileName(VarPtr(info),"debug: ",DMG_FILE_ROM))
#endif
DMG_GenerateInfoText=calloc(str.length())
str.copyToNewPtr(DMG_GenerateInfoText)
End Function
enum DMG_FILE_TYPE
DMG_FILE_ROM
DMG_FILE_SAVE
End Enum
Function MakeFileName(info As *DMG_ROM_INFO, prefix AS BytePtr, name_type AS DMG_FILE_TYPE) AS BytePtr
Dim buffer As BytePtr, i AS Long, p AS DWORD
buffer=calloc(MAX_PATH)
if prefix<>NULL Then
pstrcat(buffer,prefix,p)
endif
pstrcat(buffer,info->Title,p)
'右からスペースをNULL文字で埋めル(GBは基本的にnull terminateされているので大丈夫のハズ
For i = p To 0 Step -1
If (buffer[i] <> &H20) And (buffer[i] <> 0) Then exitfor
buffer[i] = 0
Next i
p=lstrlen(buffer)
'ファイル名に使えない文字を削除(とりあえず日本語非対応)
For i=0 to p-1
if buffer[i] < &H20 Then
buffer[i] = GetByte(" ")
End If
Next i
Dim sgb AS BytePtr
if info->ConsoleFlag And DMG_CF_SGB then
sgb = "(SGB Enhanced)"
Else
sgb = ""
endif
p+=wsprintf(buffer+p, " (%s)(V%d.%d)%s", _
DMG_GetCountryString(info->Region), _
info->RomVersion / 10, info->RomVersion Mod 10,_
sgb)
if name_type=DMG_FILE_ROM Then
if info->ConsoleFlag = DMG_CF_GBC Then
pstrcat(buffer,".gbc",p)
else
pstrcat(buffer,".gb",p)
End If
Else
pstrcat(buffer,".sav",p)
endif
EscapeForFilePath(buffer)
MakeFileName=calloc(p+1)
lstrcpy(MakeFileName,buffer)
free(buffer) : buffer=NULL
' TODO ファイル名エスケープ、MakeRomFileNameを移植、GBC拡張子をつける
End Function
'Global Checksum計算
Function DMG_CalcSum(rom AS BytePtr,Length AS Long) As Word
Dim i AS Long
Dim actualSum=0 AS Word,tmp AS Word
For i=0 To Length-1
actualSum += rom[i]
Next i
'GlobalChecksumは計算から除外
actualSum -= rom[&H014E]
actualSum -= rom[&H014F]
tmp = actualSum>>8 Or actualSum<<8
DMG_CalcSum=tmp
End Function