No Description

main.go 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. package main
  2. import (
  3. "fmt"
  4. "math"
  5. "os"
  6. // "sort"
  7. "code.beefchicken.com/keelan/68kdisasm"
  8. "encoding/json"
  9. "path/filepath"
  10. "strings"
  11. )
  12. const (
  13. bytesPerDisassemblyLine = 9
  14. )
  15. type romInfo struct {
  16. Roms []struct {
  17. File string `json:"file"`
  18. Start string `json:"start"`
  19. End string `json:"end"`
  20. Version string `json:"version"`
  21. Device string `json:"device"`
  22. Checksum string `json:"checksum"`
  23. } `json:"roms"`
  24. Labels []struct {
  25. Address string `json:"address"`
  26. Label string `json:"label"`
  27. } `json:"labels"`
  28. }
  29. type memBlock struct {
  30. lowFile string
  31. highFile string
  32. start uint32
  33. end uint32
  34. }
  35. type output struct {
  36. mnemonic string
  37. operands string
  38. comment string
  39. // these are used for "INLINE" only
  40. startPC uint32
  41. endPC uint32
  42. }
  43. type call struct {
  44. function uint32
  45. instrAddr uint32
  46. computedAddr uint32
  47. targetAddr uint32
  48. native bool
  49. }
  50. func main() {
  51. if len(os.Args) < 2 {
  52. die("Usage: %s <path to rom directory>\n", os.Args[0])
  53. }
  54. romDir := os.Args[1]
  55. romMapFilename := filepath.Join(romDir, "map.json")
  56. b, _ := os.ReadFile(romMapFilename)
  57. fmt.Printf("Loading ROM info from '%s'...\n", romMapFilename)
  58. info := &romInfo{}
  59. err := json.Unmarshal(b, &info)
  60. if err != nil {
  61. die("Unable to load rom map from '%s': %v\n", romMapFilename, err)
  62. }
  63. d := NewDisassembler()
  64. for _, rom := range info.Roms {
  65. var start, end uint32
  66. var checksum int
  67. _, err := fmt.Sscanf(rom.Start, "0x%X", &start)
  68. if err != nil {
  69. die("Unable to parse start address '%s' for rom '%s'!\n", rom.Start, rom.File)
  70. }
  71. _, err = fmt.Sscanf(rom.End, "0x%X", &end)
  72. if err != nil {
  73. die("Unable to parse end address '%s' for rom '%s'!\n", rom.End, rom.File)
  74. }
  75. _, err = fmt.Sscanf(rom.Checksum, "0x%X", &checksum)
  76. if err != nil {
  77. die("Unable to checksum '%s' for rom '%s'!\n", rom.Checksum, rom.File)
  78. }
  79. file := filepath.Join(romDir, rom.File)
  80. fmt.Printf("Loading '%s' (0x%06X-0x%06X)...\n", file, start, end)
  81. d.AddRom(file, start, end, checksum)
  82. }
  83. for _, label := range info.Labels {
  84. var address uint32
  85. _, err := fmt.Sscanf(label.Address, "0x%X", &address)
  86. if err != nil {
  87. die("Unable to parse address '%s' for label '%s!\n", label.Address, label.Label)
  88. }
  89. fmt.Printf("Adding label %s = 0x%06X\n", label.Label, address)
  90. d.AddLabel(address, label.Label)
  91. }
  92. // look for the three kinds of header functions and queue
  93. // the vm code up for disassembly
  94. queue := []uint32{}
  95. for _, block := range d.roms {
  96. for i := block.start; i <= block.end-3; i++ {
  97. inst := d.read32(i)
  98. if inst == 0x4EB82144 || inst == 0x4EB82164 || inst == 0x4EB82102 {
  99. queue = append(queue, i)
  100. }
  101. }
  102. }
  103. dests := make(map[uint32][]call)
  104. // first pass to gather all of the JSR.68Ks
  105. for _, addr := range queue {
  106. externs, _ := d.disassemble(addr, nil, true)
  107. for _, c := range externs {
  108. if !c.native {
  109. dests[c.targetAddr] = append(dests[c.targetAddr], c)
  110. }
  111. }
  112. }
  113. // disassemble with output
  114. for _, vpc := range queue {
  115. d.disassemble(vpc, dests, false)
  116. }
  117. }
  118. func die(format string, a ...any) {
  119. fmt.Printf(format, a...)
  120. os.Exit(1)
  121. }
  122. type disassembler struct {
  123. pc uint32
  124. labels map[uint32]string
  125. roms []*memBlock
  126. prog []byte
  127. caseStmts map[uint32]caseStmt
  128. }
  129. type caseStmt struct {
  130. switchAddr uint32
  131. keys []byte
  132. }
  133. func NewDisassembler() *disassembler {
  134. return &disassembler{
  135. labels: make(map[uint32]string),
  136. roms: make([]*memBlock, 0),
  137. prog: make([]byte, 0),
  138. caseStmts: make(map[uint32]caseStmt),
  139. }
  140. }
  141. func (d *disassembler) AddLabel(addr uint32, l string) {
  142. d.labels[addr] = l
  143. }
  144. func addx(x, y uint16, xf *uint16) uint16 {
  145. t := x + y + *xf
  146. if int(t) < int(x)+int(y)+int(*xf) {
  147. *xf = 1
  148. } else {
  149. *xf = 0
  150. }
  151. return t
  152. }
  153. func (d *disassembler) AddRom(file string, start uint32, end uint32, checksum int) error {
  154. // grow memory
  155. // yes this is inefficient with firmware that has sparse allocation, but for the 4000SX
  156. // it works fine.
  157. if len(d.prog) < int(end)+1 {
  158. newProg := make([]byte, end+1)
  159. copy(newProg, d.prog)
  160. d.prog = newProg
  161. }
  162. b, err := os.ReadFile(file)
  163. if err != nil {
  164. return err
  165. }
  166. var softCS, hardCS, xflag uint16
  167. for i := 0; i < len(b); i++ {
  168. d.prog[int(start)+i*2] = b[i]
  169. if i < len(b)-4 {
  170. softCS = addx(uint16(b[i]), softCS, &xflag)
  171. }
  172. hardCS += uint16(b[i])
  173. }
  174. softCS = ^softCS
  175. internalStoredChecksum := uint16(b[len(b)-1])<<8 + uint16(b[len(b)-2])
  176. // the 'soft' checksum is the one the receiver checks on boot
  177. fmt.Printf("%s Soft Checksum: got 0x%04X expected 0x%04X\n", file, softCS, internalStoredChecksum)
  178. // the 'hard' checksum is the one printed on the label on the EPROM
  179. fmt.Printf("%s Hard Checksum: got 0x%04X expected 0x%04X\n", file, hardCS, checksum)
  180. // check if we've already loaded the partner for this rom
  181. var block *memBlock
  182. for _, rom := range d.roms {
  183. if start&0xFFFFFFFE == rom.start&0xFFFFFFFE {
  184. block = rom
  185. if start < block.start {
  186. block.start = start
  187. }
  188. if end > block.end {
  189. block.end = end
  190. }
  191. break
  192. }
  193. }
  194. if block == nil {
  195. // this is the first ROM of this pair, so create the block
  196. block = &memBlock{
  197. start: start,
  198. end: end,
  199. }
  200. d.roms = append(d.roms, block)
  201. }
  202. // highfile/lowfile isn't actually used for anything, but I might want it
  203. // in the future, so I'm leaving it here.
  204. if start%2 == 0 {
  205. block.highFile = file
  206. } else {
  207. block.lowFile = file
  208. }
  209. return nil
  210. }
  211. func (d *disassembler) read8(addr uint32) byte {
  212. return d.prog[addr]
  213. }
  214. func (d *disassembler) read16(addr uint32) uint16 {
  215. return uint16(d.prog[addr])<<8 | uint16(d.prog[addr+1])
  216. }
  217. func (d *disassembler) read32(addr uint32) uint32 {
  218. return uint32(d.prog[addr])<<24 | uint32(d.prog[addr+1])<<16 | uint32(d.prog[addr+2])<<8 | uint32(d.prog[addr+3])
  219. }
  220. func (d *disassembler) read64(addr uint32) uint64 {
  221. var ret uint64
  222. ret |= uint64(d.prog[addr]) << 56
  223. ret |= uint64(d.prog[addr+1]) << 48
  224. ret |= uint64(d.prog[addr+2]) << 40
  225. ret |= uint64(d.prog[addr+3]) << 32
  226. ret |= uint64(d.prog[addr+4]) << 24
  227. ret |= uint64(d.prog[addr+5]) << 16
  228. ret |= uint64(d.prog[addr+6]) << 8
  229. ret |= uint64(d.prog[addr+7])
  230. return ret
  231. }
  232. func (d *disassembler) readFloat64(addr uint32) float64 {
  233. return math.Float64frombits(d.read64(addr))
  234. }
  235. func (d *disassembler) disassemble(start uint32, dests map[uint32][]call, silent bool) ([]call, error) {
  236. externs := make([]call, 0)
  237. signature := d.read32(start)
  238. var headerInfo string
  239. // 13fff = no branch
  240. // 14000 = branch
  241. // 14001 = branch
  242. if signature == 0x4EB82102 {
  243. if !silent {
  244. stackMax := 0x17fff
  245. vsp := stackMax + 1 - int(d.read16(start+4))
  246. if vsp < 0x14000 {
  247. vsp -= 0xc000
  248. }
  249. headerInfo = fmt.Sprintf("; A0 = $%06X; (A0) = $%04X; A6 = $%06X\n\n", 0x4000, vsp, vsp)
  250. // A0 = A6
  251. }
  252. d.pc = start + 6
  253. } else if signature == 0x4EB82144 {
  254. if !silent {
  255. a6 := 0
  256. a1 := a6 + int(d.read16(start+4)) - 1
  257. a0 := 0x4000 + (int(d.read8(start+6)) << 2)
  258. //(a0) = a1
  259. if a1 >= 0 {
  260. headerInfo = fmt.Sprintf("; A0 = $%06X; (A0) = SP + $%X\n\n", a0, a1)
  261. } else {
  262. headerInfo = fmt.Sprintf("; A0 = $%06X; (A0) = SP - $%X\n\n", a0, -a1)
  263. }
  264. }
  265. d.pc = start + 7
  266. } else if signature == 0x4EB82164 {
  267. // movea.l (SP)+,A5
  268. // move.w (A5)+,D0w
  269. // move.w (A5)+,D1w
  270. // moveq #0x0,D2
  271. // move.b (A5)+,D2b
  272. // lsl.w #0x2,D2w
  273. // movea.w #0x4000,A0
  274. // adda.w D2w,A0
  275. // move.l (A0),-(SP)=>DAT_00004000
  276. // move.w A0w,-(SP)=>local_2
  277. // movea.l A6,A1
  278. // adda.w D0w,A1
  279. // subq.l #0x1,A1
  280. // move.l A1,(A0)=>DAT_00004000
  281. // movea.l A6,A0
  282. // suba.w D1w,A6
  283. // tst.w D0w
  284. // beq.b LAB_00002196
  285. // movea.l A6,A1
  286. // lsr.w #0x1,D0w
  287. // subq.w #0x1,D0w
  288. // LAB_00002190
  289. // move.w (A0)+,(A1)+
  290. // dbf D0w,LAB_00002190
  291. // LAB_00002196
  292. // bra.w FUN_00002000
  293. if !silent {
  294. d0 := uint32(d.read16(start + 4))
  295. a6 := uint32(0)
  296. a1 := a6 + d0 - 1
  297. d1 := uint32(d.read16(start + 6))
  298. a0 := 0x4000 + (int(d.read8(start+8)) << 2)
  299. headerInfo = fmt.Sprintf("; P0 = $%04X; P1 = $%04X; P2 = $%02X\n", d.read16(start+4), d.read16(start+6), d.read8(start+8))
  300. if d0 > 0 {
  301. d0 = (d0 << 1) - 1
  302. }
  303. if a1 >= 0 {
  304. headerInfo += fmt.Sprintf("; A0 = $%06X; (A0) = A6 + $%X; D1 = $%06X\n\n", a0, a1, d1)
  305. } else {
  306. headerInfo += fmt.Sprintf("; A0 = $%06X; (A0) = A6 - $%X; D1 = $%06X\n\n", a0, -a1, d1)
  307. }
  308. }
  309. d.pc = start + 9
  310. }
  311. if !silent {
  312. fmt.Printf("\n; ---------------- Begin %04X Function $%06X ---------------- \n\n%s", signature&0xFFFF, start, headerInfo)
  313. for _, dest := range dests[start] {
  314. fmt.Printf("; called from $%06X:$%06X\n", dest.function, dest.instrAddr)
  315. }
  316. fmt.Printf("\n%6s %-*s%-8s\t%-20s%s\n\n", "; addr", bytesPerDisassemblyLine*3+2, "bytes", "opcode", "operands", "comment")
  317. }
  318. var err error
  319. for {
  320. instPC := d.pc
  321. inst := d.prog[d.pc]
  322. d.pc++
  323. o := output{}
  324. if cs, ok := d.caseStmts[instPC]; ok {
  325. if len(cs.keys) > 0 {
  326. o.mnemonic = fmt.Sprintf("CASE")
  327. o.comment = fmt.Sprintf("SWITCH $%06X", cs.switchAddr)
  328. keysStr := make([]string, len(cs.keys))
  329. for i, v := range cs.keys {
  330. keysStr[i] = fmt.Sprintf("$%02X", v)
  331. }
  332. o.operands = strings.Join(keysStr, ", ")
  333. d.pc += 1 + uint32(len(cs.keys))
  334. } else {
  335. o.mnemonic = fmt.Sprintf("DEFAULT")
  336. o.comment = fmt.Sprintf("SWITCH $%06X", cs.switchAddr)
  337. }
  338. delete(d.caseStmts, instPC)
  339. } else if inst == 0x01 {
  340. o.mnemonic = "NOP"
  341. } else if inst == 0x02 {
  342. o.mnemonic = "INLINE"
  343. if d.pc%2 != 0 {
  344. d.pc++
  345. }
  346. startPC := d.pc
  347. // find end of program
  348. for {
  349. if d.read16(d.pc) == 0x4e75 {
  350. d.pc += 2
  351. break
  352. }
  353. d.pc += 2
  354. }
  355. machineCodeBytes := d.prog[startPC:d.pc]
  356. o.startPC = startPC
  357. o.endPC = d.pc
  358. o.operands = fmt.Sprintf("%d Bytes", len(machineCodeBytes))
  359. } else if inst == 0x03 {
  360. op := d.getOpr8()
  361. if op <= 0x30 {
  362. o, externs, err = d.handle2090(d.pc-2, op, externs)
  363. } else {
  364. err = fmt.Errorf("bad 0x03 instruction")
  365. }
  366. } else if inst >= 0x04 && inst <= 0x07 {
  367. o.mnemonic = "PUSH.10"
  368. o.operands = fmt.Sprintf("$%03X", d.getOpr10())
  369. } else if inst >= 0x08 && inst <= 0x0F {
  370. o.mnemonic = fmt.Sprintf("?_$%02X", inst)
  371. op1 := d.getOpr16()
  372. op2 := d.getOpr16()
  373. if inst&(1<<2) == 0 && d.prog[d.pc] == 0 {
  374. d.pc++
  375. o.operands = fmt.Sprintf("$%04X, $%04X, $0", op1, op2)
  376. } else {
  377. o.operands = fmt.Sprintf("$%04X, $%04X", op1, op2)
  378. }
  379. } else if inst >= 0x10 && inst <= 0x17 {
  380. o.mnemonic = "BR"
  381. jd := int(d.getSignedOpr11())
  382. o.operands = fmt.Sprintf("$%03X", jd)
  383. o.comment = fmt.Sprintf("=> $%06X", uint32(int(d.pc)+jd))
  384. } else if inst >= 0x18 && inst <= 0x1F {
  385. o.mnemonic = "BRZ"
  386. jd := int(d.getSignedOpr11())
  387. o.operands = fmt.Sprintf("$%03X", jd)
  388. o.comment = fmt.Sprintf("=> $%06X", uint32(int(d.pc)+jd))
  389. } else if inst >= 0x20 && inst <= 0x3F {
  390. o, externs, err = d.handle2090(d.pc-1, inst-0x20, externs)
  391. } else if inst >= 0x40 && inst <= 0x7f {
  392. o.mnemonic = "PUSH.6"
  393. o.operands = fmt.Sprintf("$%02X", d.getOpr6())
  394. } else if inst >= 0x80 && inst <= 0xFF {
  395. w := []string{"B", "W", "L", "F"}[inst&0x03]
  396. if (inst & 0x10) == 0 {
  397. o.mnemonic = fmt.Sprintf("READ.%s", w)
  398. } else {
  399. o.mnemonic = fmt.Sprintf("WRITE.%s", w)
  400. }
  401. if inst >= 0xc0 {
  402. o.operands = fmt.Sprintf("$%04X", d.getOpr16())
  403. } else {
  404. o.operands = fmt.Sprintf("$%02X", d.getOpr8())
  405. }
  406. if (inst & 0x10) == 0 {
  407. if d.prog[d.pc] == 0 {
  408. d.pc++
  409. }
  410. }
  411. } else {
  412. err = fmt.Errorf("bad instruction")
  413. }
  414. if err != nil {
  415. if !silent {
  416. fmt.Printf("Disassembly failed at $%06X\n", instPC)
  417. }
  418. break
  419. }
  420. if !silent {
  421. d.printInstr(instPC, o)
  422. }
  423. if o.mnemonic == "RETURN" {
  424. break
  425. }
  426. }
  427. for i := range externs {
  428. externs[i].function = start
  429. }
  430. if !silent {
  431. if err != nil {
  432. fmt.Printf("\n; ---------------- Disassemly Terminated: %v ---------------- \n", err)
  433. } else {
  434. fmt.Printf("\n; ---------------- End Function $%06X ---------------- \n\n\n", start)
  435. }
  436. }
  437. return externs, err
  438. }
  439. func (d *disassembler) printInstr(instPC uint32, o output) {
  440. if o.mnemonic == "INLINE" {
  441. d.disassemble68k(instPC, o.startPC, d.prog[o.startPC:o.endPC])
  442. return
  443. }
  444. d.printy(instPC, d.pc, o.mnemonic, o.operands, o.comment)
  445. }
  446. func (d *disassembler) printy(startPC, endPC uint32, mnemonic, operands, comment string) {
  447. if comment != "" {
  448. comment = "; " + comment
  449. }
  450. bytePadding := bytesPerDisassemblyLine*3 + 2
  451. if endPC-startPC <= bytesPerDisassemblyLine {
  452. hex := fmt.Sprintf("% 02X", d.prog[startPC:endPC])
  453. fmt.Printf("%06X % -*s%-8s\t%-20s%s\n", startPC, bytePadding, hex, mnemonic, operands, comment)
  454. } else {
  455. for i := startPC; i < endPC; i += bytesPerDisassemblyLine {
  456. if i == startPC {
  457. hex := fmt.Sprintf("% 02X", d.prog[i:i+bytesPerDisassemblyLine])
  458. fmt.Printf("%06X % -*s%-8s\t%-20s%s\n", i, bytePadding, hex, mnemonic, operands, comment)
  459. } else {
  460. endAddr := i + bytesPerDisassemblyLine
  461. if endAddr > endPC {
  462. endAddr = endPC
  463. }
  464. hex := fmt.Sprintf("% 02X", d.prog[i:endAddr])
  465. fmt.Printf("%6s % -*s%-8s\n", "", bytePadding, hex, "")
  466. }
  467. }
  468. }
  469. }
  470. func (d *disassembler) getOpr6() byte {
  471. return d.prog[d.pc-1] & 0x3F
  472. }
  473. func (d *disassembler) getOpr8() byte {
  474. v := d.prog[d.pc]
  475. d.pc += 1
  476. return v
  477. }
  478. func (d *disassembler) getOpr10() uint16 {
  479. v := uint16(d.prog[d.pc-1]&0x03)<<8 | uint16(d.prog[d.pc])
  480. d.pc += 1
  481. return v
  482. }
  483. func (d *disassembler) getOpr11() uint16 {
  484. v := uint16(d.prog[d.pc-1]&0x07)<<8 | uint16(d.prog[d.pc])
  485. d.pc += 1
  486. return v
  487. }
  488. func (d *disassembler) getSignedOpr11() int16 {
  489. v := uint16(d.prog[d.pc-1]&0x07)<<8 | uint16(d.prog[d.pc])
  490. d.pc += 1
  491. if v&0x0400 != 0 {
  492. return int16(v | 0xF800)
  493. }
  494. return int16(v)
  495. }
  496. func (d *disassembler) getOpr16() uint16 {
  497. v := uint16(d.prog[d.pc])<<8 | uint16(d.prog[d.pc+1])
  498. d.pc += 2
  499. return v
  500. }
  501. func (d *disassembler) getOpr32() uint32 {
  502. v := uint32(d.prog[d.pc])<<24 | uint32(d.prog[d.pc+1])<<16 | uint32(d.prog[d.pc+2])<<8 | uint32(d.prog[d.pc+3])
  503. d.pc += 4
  504. return v
  505. }
  506. func (d *disassembler) getOpr64() uint64 {
  507. v := uint64(d.prog[d.pc]) << 56
  508. v |= uint64(d.prog[d.pc+1]) << 48
  509. v |= uint64(d.prog[d.pc+2]) << 40
  510. v |= uint64(d.prog[d.pc+3]) << 32
  511. v |= uint64(d.prog[d.pc+4]) << 24
  512. v |= uint64(d.prog[d.pc+5]) << 16
  513. v |= uint64(d.prog[d.pc+6]) << 8
  514. v |= uint64(d.prog[d.pc+7])
  515. d.pc += 8
  516. return v
  517. }
  518. func (d *disassembler) handle2090(instAddr uint32, inst byte, externs []call) (output, []call, error) {
  519. o := output{}
  520. switch inst {
  521. case 0x00:
  522. o.mnemonic = "ADD.F"
  523. case 0x01:
  524. o.mnemonic = "SUB.F"
  525. case 0x02:
  526. o.mnemonic = "MUL.F"
  527. case 0x03:
  528. o.mnemonic = "DIV.F"
  529. case 0x04:
  530. o.mnemonic = "GT.F"
  531. case 0x05:
  532. o.mnemonic = "GTE.F"
  533. case 0x06:
  534. o.mnemonic = "EQ.F"
  535. case 0x07:
  536. o.mnemonic = "ADD.L"
  537. case 0x08:
  538. o.mnemonic = "SUB.L"
  539. case 0x09:
  540. o.mnemonic = "MUL.L"
  541. case 0x0A:
  542. o.mnemonic = "EQ.L"
  543. case 0x0B:
  544. o.mnemonic = "NEQ.L"
  545. case 0x0C:
  546. o.mnemonic = "AND.L"
  547. case 0x0D:
  548. o.mnemonic = "OR.L"
  549. case 0x0E:
  550. o.mnemonic = "NOT.L"
  551. case 0x0F:
  552. o.mnemonic = "MOD.L"
  553. case 0x10:
  554. o.mnemonic = "BSR.68K"
  555. off := int(d.getOpr16())
  556. o.operands = fmt.Sprintf("$%04X", off)
  557. c := call{
  558. instrAddr: instAddr,
  559. computedAddr: uint32(int(d.pc) - off),
  560. }
  561. var targetAddrStr string
  562. if d.read16(c.computedAddr) == 0x4EF9 {
  563. c.targetAddr = d.read32(c.computedAddr + 2)
  564. targetAddrStr = fmt.Sprintf(" => $%06X", c.targetAddr)
  565. } else {
  566. c.targetAddr = c.computedAddr
  567. }
  568. label := d.labels[c.targetAddr]
  569. if label != "" {
  570. label = fmt.Sprintf(" (%s)", label)
  571. }
  572. var native string
  573. if d.read32(c.targetAddr) != 0x4EB82144 && d.read32(c.targetAddr) != 0x4EB82164 {
  574. native = " (NATIVE)"
  575. c.native = true
  576. }
  577. o.comment = fmt.Sprintf("=> $%06X%s%s%s", c.computedAddr, targetAddrStr, label, native)
  578. externs = append(externs, c)
  579. case 0x11:
  580. o.mnemonic = "SUBSP.B"
  581. o.operands = fmt.Sprintf("$%02X", d.getOpr8())
  582. case 0x12:
  583. o.mnemonic = "ADDSP.B"
  584. o.operands = fmt.Sprintf("$%02X", d.getOpr8())
  585. case 0x13:
  586. o.mnemonic = "_2300"
  587. case 0x14:
  588. o.mnemonic = "RETURN"
  589. case 0x15:
  590. o.mnemonic = "SWITCH"
  591. switchAddr := d.pc - 1
  592. tpc := d.pc
  593. for d.prog[tpc] != 0 {
  594. caseAddr := tpc
  595. op := d.read16(tpc)
  596. tpc += 2
  597. numKey := int(op & 0xF000 >> 12)
  598. recLen := int(op & 0xfff)
  599. keys := make([]byte, numKey)
  600. for i := 0; i < numKey; i++ {
  601. keys[i] = d.read8(tpc + uint32(i))
  602. }
  603. d.caseStmts[caseAddr] = caseStmt{
  604. switchAddr: switchAddr,
  605. keys: keys,
  606. }
  607. tpc += uint32(recLen)
  608. }
  609. d.caseStmts[tpc] = caseStmt{
  610. switchAddr: switchAddr,
  611. }
  612. case 0x16:
  613. o.mnemonic = "_2362"
  614. op := d.getOpr16() & 0xfff
  615. a0 := 0x4000 + ((op & 0x0C00) >> 8)
  616. o.comment = fmt.Sprintf("A0 = $%06X; (A0) = A6 + $%X\n\n", a0, 0)
  617. o.operands = fmt.Sprintf("$%04X", op)
  618. case 0x17:
  619. o.mnemonic = "_23d2"
  620. op := d.getOpr16() & 0xfff
  621. op2 := d.getOpr16()
  622. o.operands = fmt.Sprintf("$%04X, $%04X", op, op2)
  623. case 0x18:
  624. op := d.getOpr16()
  625. o.mnemonic = []string{"BLS.B", "BLS.W", "BLS.L", "BLS.W"}[op&0xc000>>14]
  626. o.operands = fmt.Sprintf("$%04X", op&0x3fff)
  627. o.comment = fmt.Sprintf("=> $%06X", int(d.pc)+int(op&0x3fff))
  628. case 0x19:
  629. o.mnemonic = "_23fc"
  630. op := d.getOpr16()
  631. op2 := d.getOpr16()
  632. o.operands = fmt.Sprintf("$%04X, $%04X", op, op2)
  633. case 0x1A:
  634. op := d.getOpr16()
  635. o.mnemonic = []string{"BGT.B", "BGT.W", "BGT.L", "BGT.W"}[op&0xc000>>14]
  636. o.operands = fmt.Sprintf("$%04X", op&0x3fff)
  637. o.comment = fmt.Sprintf("=> $%06X", int(d.pc)+int(op&0x3fff))
  638. case 0x1B:
  639. o.mnemonic = "PUSH.F"
  640. v := d.getOpr64()
  641. fv := math.Float64frombits(v)
  642. o.operands = fmt.Sprintf("$%016X", v)
  643. o.comment = fmt.Sprintf("float = %f", fv)
  644. case 0x1C:
  645. o.mnemonic = "PUSH.W"
  646. op := int(d.getOpr16())
  647. o.operands = fmt.Sprintf("$%04X", op)
  648. case 0x1D:
  649. o.mnemonic = "PUSH.L"
  650. op := int(d.getOpr32())
  651. o.operands = fmt.Sprintf("$%08X", op)
  652. case 0x1E:
  653. o.mnemonic = "PUSH.W"
  654. o.operands = "$0000"
  655. case 0x1F:
  656. o.mnemonic = "DISP"
  657. strlen := uint32(d.getOpr8())
  658. str := d.prog[d.pc : d.pc+strlen]
  659. o.operands = fmt.Sprintf(`"%s"`, string(str))
  660. d.pc += strlen
  661. case 0x20:
  662. o.mnemonic = "NEG.W"
  663. case 0x21:
  664. o.mnemonic = "LT.F"
  665. case 0x22:
  666. o.mnemonic = "LTE.F"
  667. case 0x23:
  668. o.mnemonic = "NEQ.F"
  669. case 0x24:
  670. o.mnemonic = "DIV.L"
  671. case 0x25:
  672. o.mnemonic = "LT.L"
  673. case 0x26:
  674. o.mnemonic = "GT.L"
  675. case 0x27:
  676. o.mnemonic = "LTE.L"
  677. case 0x28:
  678. o.mnemonic = "GTE.L"
  679. case 0x29:
  680. o.mnemonic = "FLOAT2LONG"
  681. case 0x2A:
  682. o.mnemonic = "LONG2FLOAT"
  683. case 0x2B:
  684. o.mnemonic = "COMPARE"
  685. op := d.getOpr16()
  686. o.operands = fmt.Sprintf("$%04X", op)
  687. case 0x2C:
  688. o.mnemonic = "NOTCOMPARE"
  689. op := d.getOpr16()
  690. o.operands = fmt.Sprintf("$%04X", op)
  691. case 0x2D:
  692. o.mnemonic = "SUBSP.W"
  693. op := d.getOpr16()
  694. o.operands = fmt.Sprintf("$%04X", op)
  695. case 0x2E:
  696. o.mnemonic = "ADDSP.W"
  697. op := d.getOpr16()
  698. o.operands = fmt.Sprintf("$%04X", op)
  699. case 0x2F:
  700. o.mnemonic = "XORL.L"
  701. case 0x30:
  702. o.mnemonic = "TRAP1"
  703. strlen := uint32(d.getOpr8())
  704. str := d.prog[d.pc : d.pc+strlen]
  705. o.operands = fmt.Sprintf("\"%s\"", string(str))
  706. d.pc += strlen
  707. default:
  708. return o, externs, fmt.Errorf("unrecognized 2090 instruction $%02X", inst)
  709. }
  710. return o, externs, nil
  711. }
  712. func (d *disassembler) disassemble68k(instPC, startPC uint32, machineCodeBytes []byte) {
  713. bus := disasm.NewAddressBus(d.prog)
  714. doneBytes := uint32(0)
  715. operand := ""
  716. if startPC-instPC > 1 {
  717. operand = "PAD"
  718. }
  719. d.printy(instPC, startPC, "INLINE", operand, "")
  720. for {
  721. startPC := uint32(startPC + doneBytes)
  722. s, n := disasm.Disassemble(disasm.M68K_CPU_TYPE_68000, int32(startPC), bus)
  723. endPC := startPC + uint32(n)
  724. d.printy(startPC, endPC, " "+s, "", "")
  725. doneBytes += uint32(n)
  726. if doneBytes == uint32(len(machineCodeBytes)) {
  727. break
  728. }
  729. }
  730. }