Gambatte: Some Trace/Disassemble fixes
[lsnes.git] / src / emulation / gambatte / disassemble.cpp
blob2d16e91da12ca27b72ef471e958214452aba3248
1 #include "disassemble-gb.hpp"
2 #include "interface/disassembler.hpp"
3 #include "library/string.hpp"
4 #include "library/hex.hpp"
5 #include <functional>
6 #include <sstream>
7 #include <iomanip>
9 namespace
11 std::string signdec(uint8_t v, bool psign = false);
12 std::string signdec(uint8_t v, bool psign)
14 if(v < 128) return (stringfmt() << (psign ? "+" : "") << (int)v).str();
15 return (stringfmt() << (int)v - 256).str();
18 uint16_t jraddr(uint16_t pc, uint8_t lt)
20 return pc + lt + 2 - ((lt < 128) ? 0 : 256);
23 const char* instructions[] = {
24 "NOP", "LD BC, %w", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,%b", "RCLA",
25 "LD (%W),SP", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,%b", "RRCA",
26 "STOP", "LD DE, %w", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,%b", "RLA",
27 "JR %R", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,%b", "RRA",
28 "JR NZ,%R", "LD HL, %w", "LD (HL+),A", "INC HL", "INC H", "DEC H", "LD H,%b", "DAA",
29 "JR Z,%R", "ADD HL,HL", "LD A,(HL+)", "DEC HL", "INC L", "DEC L", "LD L,%b", "CPL",
30 "JR NC,%R", "LD SP, %w", "LD (HL-),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),%b", "SCF",
31 "JR Z,%R", "ADD HL,SP", "LD A,(HL-)", "DEC SP", "INC A", "DEC A", "LD A,%b", "CCF",
33 "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A",
34 "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A",
35 "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A",
36 "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A",
37 "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A",
38 "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A",
39 "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A",
40 "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A",
42 "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD (HL)", "ADD A",
43 "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC (HL)", "ADC A",
44 "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A",
45 "SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A",
46 "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A",
47 "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A",
48 "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A",
49 "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A",
51 "RET NZ", "POP BC", "JP NZ,%w", "JP %w", "CALL NZ,%w", "PUSH BC", "ADD %b", "RST 0x00",
52 "RET Z", "RET", "JP Z,%w", "", "CALL Z,%w", "CALL %w", "ADC %b", "RST 0x08",
53 "RET NC", "POP DE", "JP NC,%w", "INVALID_D3", "CALL NC,%w", "PUSH DE", "SUB %b", "RST 0x10",
54 "RET C", "RETI", "JP C,%w", "INVALID_DB", "CALL C,%w", "INVALID_DD", "SBC %b", "RST 0x18",
55 "LDH (%B),A", "POP HL", "LD (C),A", "INVALID_E3", "INVALID_E4", "PUSH HL", "AND %b", "RST 0x20",
56 "ADD SP,%s", "JP (HL)", "LD (%W),A", "INVALID_EB", "INVALID_EC", "INVALID_ED", "XOR %b", "RST 0x28",
57 "LDH A, (%B)", "POP AF", "LD A,(C)", "DI", "INVALID_F4", "PUSH AF", "OR %b", "RST 0x30",
58 "LD HL,SP%S", "LD SP,HL", "LD A,(%W)", "EI", "INVALID_FC", "INVALID_FD", "CP %b", "RST 0x38",
62 std::string disassemble_gb_opcode(uint16_t pc, std::function<uint8_t()> fetch, int& addr, uint16_t& opc)
64 std::function<uint16_t()> fetch2 = [&fetch]() -> uint16_t {
65 uint8_t lt, ht;
66 lt = fetch();
67 ht = fetch();
68 return 256 * ht + lt;
70 uint8_t opcode = fetch();
71 opc = (uint16_t)opcode << 8;
72 if(opcode == 0xCB) {
73 //Bit ops.
74 static const char* regs[] = {"B", "C", "D", "E", "H", "L", "(HL)", "A"};
75 opcode = fetch();
76 opc |= opcode;
77 uint8_t block = opcode >> 6;
78 uint8_t bit = (opcode >> 3) & 7;
79 uint8_t reg = opcode & 7;
80 switch(block) {
81 case 0:
82 switch(bit) {
83 case 0: return (stringfmt() << "RLC " << regs[reg]).str();
84 case 1: return (stringfmt() << "RRC " << regs[reg]).str();
85 case 2: return (stringfmt() << "RL " << regs[reg]).str();
86 case 3: return (stringfmt() << "RR " << regs[reg]).str();
87 case 4: return (stringfmt() << "SLA " << regs[reg]).str();
88 case 5: return (stringfmt() << "SRA " << regs[reg]).str();
89 case 6: return (stringfmt() << "SWAP " << regs[reg]).str();
90 case 7: return (stringfmt() << "SRL " << regs[reg]).str();
92 case 1: return (stringfmt() << "BIT " << (int)bit << "," << regs[reg]).str();
93 case 2: return (stringfmt() << "RES " << (int)bit << "," << regs[reg]).str();
94 case 3: return (stringfmt() << "SET " << (int)bit << "," << regs[reg]).str();
97 std::ostringstream o;
98 const char* ins = instructions[opcode];
99 uint16_t tmp;
100 for(size_t i = 0; ins[i]; i++) {
101 if(ins[i] != '%')
102 o << ins[i];
103 else {
104 switch(ins[i + 1]) {
105 case 'b':
106 o << "0x" << hex::to8(fetch());
107 break;
108 case 'B':
109 o << "0x" << hex::to8(tmp = fetch());
110 addr = 0xFF00 + tmp;
111 break;
112 case 'w':
113 o << "0x" << hex::to16(fetch2());
114 break;
115 case 'W':
116 o << "0x" << hex::to16(tmp = fetch2());
117 addr = tmp;
118 break;
119 case 'R':
120 o << signdec(tmp = fetch(), false);
121 addr = jraddr(pc, tmp);
122 break;
123 case 's':
124 o << signdec(tmp = fetch(), false);
125 break;
126 case 'S':
127 o << signdec(tmp = fetch(), true);
128 break;
130 i++;
133 return o.str();
136 namespace
138 struct gb_disassembler : public disassembler
140 gb_disassembler() : disassembler("gb") {}
141 std::string disassemble(uint64_t base, std::function<unsigned char()> fetchpc)
143 int dummy;
144 uint16_t dummy2;
145 return disassemble_gb_opcode(base, fetchpc, dummy, dummy2);
147 } gb_disasm;