|
@@ -5,13 +5,15 @@ import (
|
5
|
5
|
"math"
|
6
|
6
|
"os"
|
7
|
7
|
// "sort"
|
8
|
|
- "strings"
|
9
|
|
- //"code.beefchicken.com/68kdisasm"
|
|
8
|
+ "code.beefchicken.com/keelan/68kdisasm"
|
10
|
9
|
"encoding/json"
|
11
|
10
|
"path/filepath"
|
|
11
|
+ "strings"
|
12
|
12
|
)
|
13
|
13
|
|
14
|
|
-//var externs = make([]int, 0)
|
|
14
|
+const (
|
|
15
|
+ bytesPerDisassemblyLine = 9
|
|
16
|
+)
|
15
|
17
|
|
16
|
18
|
type romInfo struct {
|
17
|
19
|
Roms []struct {
|
|
@@ -39,6 +41,10 @@ type output struct {
|
39
|
41
|
mnemonic string
|
40
|
42
|
operands string
|
41
|
43
|
comment string
|
|
44
|
+
|
|
45
|
+ // these are used for "INLINE" only
|
|
46
|
+ startPC uint32
|
|
47
|
+ endPC uint32
|
42
|
48
|
}
|
43
|
49
|
|
44
|
50
|
type call struct {
|
|
@@ -52,46 +58,50 @@ type call struct {
|
52
|
58
|
func main() {
|
53
|
59
|
|
54
|
60
|
if len(os.Args) < 2 {
|
55
|
|
- fmt.Printf("Usage: %s <path to rom directory>\n", os.Args[0])
|
56
|
|
- os.Exit(1)
|
|
61
|
+ die("Usage: %s <path to rom directory>\n", os.Args[0])
|
57
|
62
|
}
|
|
63
|
+
|
58
|
64
|
romDir := os.Args[1]
|
59
|
|
- romMapFilename := filepath.Join(romDir, "map.json")
|
60
|
|
- info := &romInfo{}
|
61
|
65
|
|
|
66
|
+ romMapFilename := filepath.Join(romDir, "map.json")
|
62
|
67
|
b, _ := os.ReadFile(romMapFilename)
|
63
|
68
|
|
64
|
69
|
fmt.Printf("Loading ROM info from '%s'...\n", romMapFilename)
|
|
70
|
+
|
|
71
|
+ info := &romInfo{}
|
65
|
72
|
err := json.Unmarshal(b, &info)
|
66
|
73
|
if err != nil {
|
67
|
|
- fmt.Printf("unable to load rom map from '%s': %v\n", romMapFilename, err)
|
68
|
|
- os.Exit(1)
|
|
74
|
+ die("Unable to load rom map from '%s': %v\n", romMapFilename, err)
|
69
|
75
|
}
|
70
|
76
|
|
71
|
77
|
d := NewDisassembler()
|
72
|
78
|
|
73
|
79
|
for _, rom := range info.Roms {
|
|
80
|
+
|
74
|
81
|
var start, end uint32
|
75
|
82
|
var checksum int
|
76
|
83
|
|
77
|
84
|
_, err := fmt.Sscanf(rom.Start, "0x%X", &start)
|
78
|
85
|
if err != nil {
|
79
|
|
- fmt.Printf("Unable to parse start address '%s' for rom '%s'!\n", rom.Start, rom.File)
|
80
|
|
- os.Exit(1)
|
|
86
|
+ die("Unable to parse start address '%s' for rom '%s'!\n", rom.Start, rom.File)
|
81
|
87
|
}
|
|
88
|
+
|
82
|
89
|
_, err = fmt.Sscanf(rom.End, "0x%X", &end)
|
83
|
90
|
if err != nil {
|
84
|
|
- fmt.Printf("Unable to parse end address '%s' for rom '%s'!\n", rom.End, rom.File)
|
85
|
|
- os.Exit(1)
|
|
91
|
+ die("Unable to parse end address '%s' for rom '%s'!\n", rom.End, rom.File)
|
86
|
92
|
}
|
|
93
|
+
|
87
|
94
|
_, err = fmt.Sscanf(rom.Checksum, "0x%X", &checksum)
|
88
|
95
|
if err != nil {
|
89
|
|
- fmt.Printf("Unable to checksum '%s' for rom '%s'!\n", rom.Checksum, rom.File)
|
90
|
|
- os.Exit(1)
|
|
96
|
+ die("Unable to checksum '%s' for rom '%s'!\n", rom.Checksum, rom.File)
|
91
|
97
|
}
|
|
98
|
+
|
92
|
99
|
file := filepath.Join(romDir, rom.File)
|
|
100
|
+
|
93
|
101
|
fmt.Printf("Loading '%s' (0x%06X-0x%06X)...\n", file, start, end)
|
|
102
|
+
|
94
|
103
|
d.AddRom(file, start, end, checksum)
|
|
104
|
+
|
95
|
105
|
}
|
96
|
106
|
|
97
|
107
|
for _, label := range info.Labels {
|
|
@@ -99,17 +109,16 @@ func main() {
|
99
|
109
|
var address uint32
|
100
|
110
|
_, err := fmt.Sscanf(label.Address, "0x%X", &address)
|
101
|
111
|
if err != nil {
|
102
|
|
- fmt.Printf("Unable to parse address '%s' for label '%s!\n", label.Address, label.Label)
|
103
|
|
- os.Exit(1)
|
|
112
|
+ die("Unable to parse address '%s' for label '%s!\n", label.Address, label.Label)
|
104
|
113
|
}
|
105
|
114
|
fmt.Printf("Adding label %s = 0x%06X\n", label.Label, address)
|
106
|
115
|
d.AddLabel(address, label.Label)
|
107
|
116
|
|
108
|
117
|
}
|
109
|
118
|
|
110
|
|
- // look for the two kinds of header functions and queue
|
|
119
|
+ // look for the three kinds of header functions and queue
|
111
|
120
|
// the vm code up for disassembly
|
112
|
|
- queue := []uint32{} //0xe6d // 0xa0435 <- week // 0x00001631 <- WRNO FIX // 0x0009324d
|
|
121
|
+ queue := []uint32{}
|
113
|
122
|
for _, block := range d.roms {
|
114
|
123
|
for i := block.start; i <= block.end-3; i++ {
|
115
|
124
|
inst := d.read32(i)
|
|
@@ -138,6 +147,11 @@ func main() {
|
138
|
147
|
|
139
|
148
|
}
|
140
|
149
|
|
|
150
|
+func die(format string, a ...any) {
|
|
151
|
+ fmt.Printf(format, a...)
|
|
152
|
+ os.Exit(1)
|
|
153
|
+}
|
|
154
|
+
|
141
|
155
|
type disassembler struct {
|
142
|
156
|
pc uint32
|
143
|
157
|
labels map[uint32]string
|
|
@@ -176,6 +190,9 @@ func addx(x, y uint16, xf *uint16) uint16 {
|
176
|
190
|
|
177
|
191
|
func (d *disassembler) AddRom(file string, start uint32, end uint32, checksum int) error {
|
178
|
192
|
|
|
193
|
+ // grow memory
|
|
194
|
+ // yes this is inefficient with firmware that has sparse allocation, but for the 4000SX
|
|
195
|
+ // it works fine.
|
179
|
196
|
if len(d.prog) < int(end)+1 {
|
180
|
197
|
newProg := make([]byte, end+1)
|
181
|
198
|
copy(newProg, d.prog)
|
|
@@ -187,26 +204,26 @@ func (d *disassembler) AddRom(file string, start uint32, end uint32, checksum in
|
187
|
204
|
return err
|
188
|
205
|
}
|
189
|
206
|
|
190
|
|
- var cs uint16 = 0
|
191
|
|
- var cs2 uint16 = 0
|
192
|
|
-
|
193
|
|
- var xf uint16
|
|
207
|
+ var softCS, hardCS, xflag uint16
|
194
|
208
|
|
195
|
209
|
for i := 0; i < len(b); i++ {
|
196
|
210
|
d.prog[int(start)+i*2] = b[i]
|
197
|
211
|
if i < len(b)-4 {
|
198
|
|
- cs = addx(uint16(b[i]), cs, &xf)
|
|
212
|
+ softCS = addx(uint16(b[i]), softCS, &xflag)
|
199
|
213
|
}
|
200
|
|
- cs2 += uint16(b[i])
|
|
214
|
+ hardCS += uint16(b[i])
|
201
|
215
|
}
|
202
|
|
- cs = ^cs
|
|
216
|
+ softCS = ^softCS
|
203
|
217
|
|
204
|
218
|
internalStoredChecksum := uint16(b[len(b)-1])<<8 + uint16(b[len(b)-2])
|
205
|
219
|
|
206
|
|
- fmt.Printf("%s INTERNAL CHECKSUM: GOT 0x%04X EXPECTED 0x%04X\n", file, cs, internalStoredChecksum)
|
207
|
|
- fmt.Printf("%s EXTERNAL CHECKSUM: GOT 0x%04X EXPECTED 0x%04X\n", file, cs2, checksum)
|
|
220
|
+ // the 'soft' checksum is the one the receiver checks on boot
|
|
221
|
+ fmt.Printf("%s Soft Checksum: got 0x%04X expected 0x%04X\n", file, softCS, internalStoredChecksum)
|
208
|
222
|
|
209
|
|
- // check if we've already loaded the pair for this rom
|
|
223
|
+ // the 'hard' checksum is the one printed on the label on the EPROM
|
|
224
|
+ fmt.Printf("%s Hard Checksum: got 0x%04X expected 0x%04X\n", file, hardCS, checksum)
|
|
225
|
+
|
|
226
|
+ // check if we've already loaded the partner for this rom
|
210
|
227
|
var block *memBlock
|
211
|
228
|
for _, rom := range d.roms {
|
212
|
229
|
if start&0xFFFFFFFE == rom.start&0xFFFFFFFE {
|
|
@@ -230,10 +247,12 @@ func (d *disassembler) AddRom(file string, start uint32, end uint32, checksum in
|
230
|
247
|
d.roms = append(d.roms, block)
|
231
|
248
|
}
|
232
|
249
|
|
|
250
|
+ // highfile/lowfile isn't actually used for anything, but I might want it
|
|
251
|
+ // in the future, so I'm leaving it here.
|
233
|
252
|
if start%2 == 0 {
|
234
|
|
- block.lowFile = file
|
235
|
|
- } else {
|
236
|
253
|
block.highFile = file
|
|
254
|
+ } else {
|
|
255
|
+ block.lowFile = file
|
237
|
256
|
}
|
238
|
257
|
|
239
|
258
|
return nil
|
|
@@ -251,10 +270,6 @@ func (d *disassembler) read32(addr uint32) uint32 {
|
251
|
270
|
return uint32(d.prog[addr])<<24 | uint32(d.prog[addr+1])<<16 | uint32(d.prog[addr+2])<<8 | uint32(d.prog[addr+3])
|
252
|
271
|
}
|
253
|
272
|
|
254
|
|
-func (d *disassembler) readFloat64(addr uint32) float64 {
|
255
|
|
- return math.Float64frombits(d.read64(addr))
|
256
|
|
-}
|
257
|
|
-
|
258
|
273
|
func (d *disassembler) read64(addr uint32) uint64 {
|
259
|
274
|
var ret uint64
|
260
|
275
|
|
|
@@ -270,6 +285,10 @@ func (d *disassembler) read64(addr uint32) uint64 {
|
270
|
285
|
return ret
|
271
|
286
|
}
|
272
|
287
|
|
|
288
|
+func (d *disassembler) readFloat64(addr uint32) float64 {
|
|
289
|
+ return math.Float64frombits(d.read64(addr))
|
|
290
|
+}
|
|
291
|
+
|
273
|
292
|
func (d *disassembler) disassemble(start uint32, dests map[uint32][]call, silent bool) ([]call, error) {
|
274
|
293
|
|
275
|
294
|
externs := make([]call, 0)
|
|
@@ -368,7 +387,7 @@ func (d *disassembler) disassemble(start uint32, dests map[uint32][]call, silent
|
368
|
387
|
|
369
|
388
|
}
|
370
|
389
|
|
371
|
|
- fmt.Printf("\n%6s %-14s %-8s\t%-20s%s\n\n", "; addr", "bytes", "opcode", "operands", "comment")
|
|
390
|
+ fmt.Printf("\n%6s %-*s%-8s\t%-20s%s\n\n", "; addr", bytesPerDisassemblyLine*3+2, "bytes", "opcode", "operands", "comment")
|
372
|
391
|
|
373
|
392
|
}
|
374
|
393
|
|
|
@@ -405,32 +424,24 @@ func (d *disassembler) disassemble(start uint32, dests map[uint32][]call, silent
|
405
|
424
|
if d.pc%2 != 0 {
|
406
|
425
|
d.pc++
|
407
|
426
|
}
|
408
|
|
- //startPC := d.pc
|
409
|
|
- machineCodeBytes := make([]byte, 0)
|
|
427
|
+
|
|
428
|
+ startPC := d.pc
|
|
429
|
+
|
|
430
|
+ // find end of program
|
410
|
431
|
for {
|
411
|
|
- machineCodeBytes = append(machineCodeBytes, d.prog[d.pc])
|
412
|
432
|
if d.read16(d.pc) == 0x4e75 {
|
413
|
|
- machineCodeBytes = append(machineCodeBytes, d.prog[d.pc+1])
|
414
|
433
|
d.pc += 2
|
415
|
434
|
break
|
416
|
435
|
}
|
417
|
|
- d.pc++
|
|
436
|
+ d.pc += 2
|
418
|
437
|
}
|
419
|
438
|
|
420
|
|
- // bus := disasm.NewAddressBus(d.prog)
|
421
|
|
- // doneBytes := 0
|
422
|
|
- //
|
423
|
|
- // for {
|
424
|
|
- // s, n := disasm.Disassemble(disasm.M68K_CPU_TYPE_68000, int32(startPC+doneBytes), bus)
|
425
|
|
- // fmt.Println(s)
|
426
|
|
- // doneBytes+=int(n)
|
427
|
|
- // if doneBytes == len(machineCodeBytes) {
|
428
|
|
- // break
|
429
|
|
- // }
|
430
|
|
- // }
|
431
|
|
-
|
432
|
|
- //fmt.Printf("%d % 02X\n",len(machineCodeBytes),machineCodeBytes)
|
433
|
|
- o.operands = fmt.Sprintf("%d Bytes", len(machineCodeBytes)) //d.getOpr32())
|
|
439
|
+ machineCodeBytes := d.prog[startPC:d.pc]
|
|
440
|
+
|
|
441
|
+ o.startPC = startPC
|
|
442
|
+ o.endPC = d.pc
|
|
443
|
+
|
|
444
|
+ o.operands = fmt.Sprintf("%d Bytes", len(machineCodeBytes))
|
434
|
445
|
} else if inst == 0x03 {
|
435
|
446
|
op := d.getOpr8()
|
436
|
447
|
if op <= 0x30 {
|
|
@@ -492,35 +503,6 @@ func (d *disassembler) disassemble(start uint32, dests map[uint32][]call, silent
|
492
|
503
|
err = fmt.Errorf("bad instruction")
|
493
|
504
|
}
|
494
|
505
|
|
495
|
|
- // var hex string
|
496
|
|
-
|
497
|
|
- // if !silent {
|
498
|
|
- // if d.pc-instPC < 6 {
|
499
|
|
- // hex = fmt.Sprintf("% 02X", d.prog[instPC:d.pc])
|
500
|
|
- // } else {
|
501
|
|
- // hex = fmt.Sprintf("% 02X...", d.prog[instPC:instPC+4])
|
502
|
|
- // }
|
503
|
|
- // fmt.Printf("%06X % -14s ", instPC, hex)
|
504
|
|
- // }
|
505
|
|
- //
|
506
|
|
- // if err != nil {
|
507
|
|
- // break
|
508
|
|
- // }
|
509
|
|
- //
|
510
|
|
- // if !silent {
|
511
|
|
- // var comment string
|
512
|
|
- // if o.comment != "" {
|
513
|
|
- // comment = "; " + o.comment
|
514
|
|
- // }
|
515
|
|
- // fmt.Printf("%-8s\t%-20s%s\n", o.mnemonic, o.operands, comment)
|
516
|
|
- // }
|
517
|
|
-
|
518
|
|
- if err == nil {
|
519
|
|
- if !silent {
|
520
|
|
- d.printInstr(instPC, o)
|
521
|
|
- }
|
522
|
|
- }
|
523
|
|
-
|
524
|
506
|
if err != nil {
|
525
|
507
|
if !silent {
|
526
|
508
|
fmt.Printf("Disassembly failed at $%06X\n", instPC)
|
|
@@ -528,6 +510,10 @@ func (d *disassembler) disassemble(start uint32, dests map[uint32][]call, silent
|
528
|
510
|
break
|
529
|
511
|
}
|
530
|
512
|
|
|
513
|
+ if !silent {
|
|
514
|
+ d.printInstr(instPC, o)
|
|
515
|
+ }
|
|
516
|
+
|
531
|
517
|
if o.mnemonic == "RETURN" {
|
532
|
518
|
break
|
533
|
519
|
}
|
|
@@ -550,49 +536,41 @@ func (d *disassembler) disassemble(start uint32, dests map[uint32][]call, silent
|
550
|
536
|
|
551
|
537
|
func (d *disassembler) printInstr(instPC uint32, o output) {
|
552
|
538
|
|
553
|
|
- // var hex, comment string
|
554
|
|
- // if o.comment != "" {
|
555
|
|
- // comment = "; " + o.comment
|
556
|
|
- // }
|
557
|
|
- //
|
558
|
|
- // if d.pc-instPC < 6 {
|
559
|
|
- // hex = fmt.Sprintf("% 02X", d.prog[instPC:d.pc])
|
560
|
|
- // } else {
|
561
|
|
- // hex = fmt.Sprintf("% 02X...", d.prog[instPC:instPC+4])
|
562
|
|
- // }
|
563
|
|
- // fmt.Printf("%06X % -14s ", instPC, hex)
|
564
|
|
- //
|
565
|
|
- //
|
566
|
|
- // fmt.Printf("%-8s\t%-20s%s\n", o.mnemonic, o.operands, comment)
|
567
|
|
-
|
568
|
|
- var hex, comment string
|
569
|
|
- if o.comment != "" {
|
570
|
|
- comment = "; " + o.comment
|
|
539
|
+ if o.mnemonic == "INLINE" {
|
|
540
|
+ d.disassemble68k(instPC, o.startPC, d.prog[o.startPC:o.endPC])
|
|
541
|
+ return
|
571
|
542
|
}
|
572
|
543
|
|
573
|
|
- if d.pc-instPC < 6 {
|
574
|
|
- hex = fmt.Sprintf("% 02X", d.prog[instPC:d.pc])
|
575
|
|
- fmt.Printf("%06X % -14s %-8s\t%-20s%s\n", instPC, hex, o.mnemonic, o.operands, comment)
|
|
544
|
+ d.printy(instPC, d.pc, o.mnemonic, o.operands, o.comment)
|
|
545
|
+
|
|
546
|
+}
|
|
547
|
+
|
|
548
|
+func (d *disassembler) printy(startPC, endPC uint32, mnemonic, operands, comment string) {
|
|
549
|
+ if comment != "" {
|
|
550
|
+ comment = "; " + comment
|
|
551
|
+ }
|
|
552
|
+ bytePadding := bytesPerDisassemblyLine*3 + 2
|
|
553
|
+ if endPC-startPC <= bytesPerDisassemblyLine {
|
|
554
|
+ hex := fmt.Sprintf("% 02X", d.prog[startPC:endPC])
|
|
555
|
+ fmt.Printf("%06X % -*s%-8s\t%-20s%s\n", startPC, bytePadding, hex, mnemonic, operands, comment)
|
576
|
556
|
} else {
|
577
|
|
- for i := instPC; i < d.pc; i += 5 {
|
578
|
|
- if i == instPC {
|
579
|
|
- hex = fmt.Sprintf("% 02X", d.prog[i:i+5])
|
580
|
|
- fmt.Printf("%06X % -14s %-8s\t%-20s%s\n", i, hex, o.mnemonic, o.operands, comment)
|
|
557
|
+ for i := startPC; i < endPC; i += bytesPerDisassemblyLine {
|
|
558
|
+ if i == startPC {
|
|
559
|
+ hex := fmt.Sprintf("% 02X", d.prog[i:i+bytesPerDisassemblyLine])
|
|
560
|
+ fmt.Printf("%06X % -*s%-8s\t%-20s%s\n", i, bytePadding, hex, mnemonic, operands, comment)
|
581
|
561
|
} else {
|
582
|
|
- endAddr := i + 5
|
583
|
|
- if endAddr > d.pc {
|
584
|
|
- endAddr = d.pc
|
|
562
|
+ endAddr := i + bytesPerDisassemblyLine
|
|
563
|
+ if endAddr > endPC {
|
|
564
|
+ endAddr = endPC
|
585
|
565
|
}
|
586
|
|
- hex = fmt.Sprintf("% 02X", d.prog[i:endAddr])
|
587
|
|
- //fmt.Printf("%06X % -14s %-8s\n", i, hex, "")
|
588
|
|
- fmt.Printf("%6s % -14s %-8s\n", "", hex, "")
|
|
566
|
+ hex := fmt.Sprintf("% 02X", d.prog[i:endAddr])
|
|
567
|
+ fmt.Printf("%6s % -*s%-8s\n", "", bytePadding, hex, "")
|
589
|
568
|
|
590
|
569
|
}
|
591
|
570
|
|
592
|
571
|
}
|
593
|
572
|
|
594
|
573
|
}
|
595
|
|
-
|
596
|
574
|
}
|
597
|
575
|
|
598
|
576
|
func (d *disassembler) getOpr6() byte {
|
|
@@ -855,3 +833,29 @@ func (d *disassembler) handle2090(instAddr uint32, inst byte, externs []call) (o
|
855
|
833
|
}
|
856
|
834
|
return o, externs, nil
|
857
|
835
|
}
|
|
836
|
+
|
|
837
|
+func (d *disassembler) disassemble68k(instPC, startPC uint32, machineCodeBytes []byte) {
|
|
838
|
+ bus := disasm.NewAddressBus(d.prog)
|
|
839
|
+ doneBytes := uint32(0)
|
|
840
|
+
|
|
841
|
+ operand := ""
|
|
842
|
+
|
|
843
|
+ if startPC-instPC > 1 {
|
|
844
|
+ operand = "PAD"
|
|
845
|
+ }
|
|
846
|
+ d.printy(instPC, startPC, "INLINE", operand, "")
|
|
847
|
+
|
|
848
|
+ for {
|
|
849
|
+ startPC := uint32(startPC + doneBytes)
|
|
850
|
+ s, n := disasm.Disassemble(disasm.M68K_CPU_TYPE_68000, int32(startPC), bus)
|
|
851
|
+ endPC := startPC + uint32(n)
|
|
852
|
+
|
|
853
|
+ d.printy(startPC, endPC, " "+s, "", "")
|
|
854
|
+
|
|
855
|
+ doneBytes += uint32(n)
|
|
856
|
+ if doneBytes == uint32(len(machineCodeBytes)) {
|
|
857
|
+ break
|
|
858
|
+ }
|
|
859
|
+ }
|
|
860
|
+
|
|
861
|
+}
|