No Description

main.go 20KB

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