]>
Commit | Line | Data |
---|---|---|
9d8caa67 MR |
1 | /* |
2 | * AVR disassembler | |
3 | * | |
4 | * Copyright (c) 2019-2020 Richard Henderson <[email protected]> | |
5 | * Copyright (c) 2019-2020 Michael Rolnik <[email protected]> | |
6 | * | |
7 | * This program is free software: you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation, either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
21 | #include "qemu/osdep.h" | |
22 | #include "cpu.h" | |
23 | ||
24 | typedef struct { | |
25 | disassemble_info *info; | |
26 | uint16_t next_word; | |
27 | bool next_word_used; | |
28 | } DisasContext; | |
29 | ||
30 | static int to_regs_16_31_by_one(DisasContext *ctx, int indx) | |
31 | { | |
32 | return 16 + (indx % 16); | |
33 | } | |
34 | ||
35 | static int to_regs_16_23_by_one(DisasContext *ctx, int indx) | |
36 | { | |
37 | return 16 + (indx % 8); | |
38 | } | |
39 | ||
40 | static int to_regs_24_30_by_two(DisasContext *ctx, int indx) | |
41 | { | |
42 | return 24 + (indx % 4) * 2; | |
43 | } | |
44 | ||
45 | static int to_regs_00_30_by_two(DisasContext *ctx, int indx) | |
46 | { | |
47 | return (indx % 16) * 2; | |
48 | } | |
49 | ||
50 | static uint16_t next_word(DisasContext *ctx) | |
51 | { | |
52 | ctx->next_word_used = true; | |
53 | return ctx->next_word; | |
54 | } | |
55 | ||
56 | static int append_16(DisasContext *ctx, int x) | |
57 | { | |
58 | return x << 16 | next_word(ctx); | |
59 | } | |
60 | ||
61 | /* Include the auto-generated decoder. */ | |
62 | static bool decode_insn(DisasContext *ctx, uint16_t insn); | |
63 | #include "decode_insn.inc.c" | |
64 | ||
65 | #define output(mnemonic, format, ...) \ | |
66 | (pctx->info->fprintf_func(pctx->info->stream, "%-9s " format, \ | |
67 | mnemonic, ##__VA_ARGS__)) | |
68 | ||
69 | int avr_print_insn(bfd_vma addr, disassemble_info *info) | |
70 | { | |
71 | DisasContext ctx; | |
72 | DisasContext *pctx = &ctx; | |
73 | bfd_byte buffer[4]; | |
74 | uint16_t insn; | |
75 | int status; | |
76 | ||
77 | ctx.info = info; | |
78 | ||
79 | status = info->read_memory_func(addr, buffer, 4, info); | |
80 | if (status != 0) { | |
81 | info->memory_error_func(status, addr, info); | |
82 | return -1; | |
83 | } | |
84 | insn = bfd_getl16(buffer); | |
85 | ctx.next_word = bfd_getl16(buffer + 2); | |
86 | ctx.next_word_used = false; | |
87 | ||
88 | if (!decode_insn(&ctx, insn)) { | |
89 | output(".db", "0x%02x, 0x%02x", buffer[0], buffer[1]); | |
90 | } | |
91 | ||
92 | return ctx.next_word_used ? 4 : 2; | |
93 | } | |
94 | ||
95 | ||
96 | #define INSN(opcode, format, ...) \ | |
97 | static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ | |
98 | { \ | |
99 | output(#opcode, format, ##__VA_ARGS__); \ | |
100 | return true; \ | |
101 | } | |
102 | ||
103 | #define INSN_MNEMONIC(opcode, mnemonic, format, ...) \ | |
104 | static bool trans_##opcode(DisasContext *pctx, arg_##opcode * a) \ | |
105 | { \ | |
106 | output(mnemonic, format, ##__VA_ARGS__); \ | |
107 | return true; \ | |
108 | } | |
109 | ||
110 | /* | |
111 | * C Z N V S H T I | |
112 | * 0 1 2 3 4 5 6 7 | |
113 | */ | |
114 | static const char brbc[][5] = { | |
115 | "BRCC", "BRNE", "BRPL", "BRVC", "BRGE", "BRHC", "BRTC", "BRID" | |
116 | }; | |
117 | ||
118 | static const char brbs[][5] = { | |
119 | "BRCS", "BREQ", "BRMI", "BRVS", "BRLT", "BRHS", "BRTS", "BRIE" | |
120 | }; | |
121 | ||
122 | static const char bset[][4] = { | |
123 | "SEC", "SEZ", "SEN", "SEZ", "SES", "SEH", "SET", "SEI" | |
124 | }; | |
125 | ||
126 | static const char bclr[][4] = { | |
127 | "CLC", "CLZ", "CLN", "CLZ", "CLS", "CLH", "CLT", "CLI" | |
128 | }; | |
129 | ||
130 | /* | |
131 | * Arithmetic Instructions | |
132 | */ | |
133 | INSN(ADD, "r%d, r%d", a->rd, a->rr) | |
134 | INSN(ADC, "r%d, r%d", a->rd, a->rr) | |
135 | INSN(ADIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) | |
136 | INSN(SUB, "r%d, r%d", a->rd, a->rr) | |
137 | INSN(SUBI, "r%d, %d", a->rd, a->imm) | |
138 | INSN(SBC, "r%d, r%d", a->rd, a->rr) | |
139 | INSN(SBCI, "r%d, %d", a->rd, a->imm) | |
140 | INSN(SBIW, "r%d:r%d, %d", a->rd + 1, a->rd, a->imm) | |
141 | INSN(AND, "r%d, r%d", a->rd, a->rr) | |
142 | INSN(ANDI, "r%d, %d", a->rd, a->imm) | |
143 | INSN(OR, "r%d, r%d", a->rd, a->rr) | |
144 | INSN(ORI, "r%d, %d", a->rd, a->imm) | |
145 | INSN(EOR, "r%d, r%d", a->rd, a->rr) | |
146 | INSN(COM, "r%d", a->rd) | |
147 | INSN(NEG, "r%d", a->rd) | |
148 | INSN(INC, "r%d", a->rd) | |
149 | INSN(DEC, "r%d", a->rd) | |
150 | INSN(MUL, "r%d, r%d", a->rd, a->rr) | |
151 | INSN(MULS, "r%d, r%d", a->rd, a->rr) | |
152 | INSN(MULSU, "r%d, r%d", a->rd, a->rr) | |
153 | INSN(FMUL, "r%d, r%d", a->rd, a->rr) | |
154 | INSN(FMULS, "r%d, r%d", a->rd, a->rr) | |
155 | INSN(FMULSU, "r%d, r%d", a->rd, a->rr) | |
156 | INSN(DES, "%d", a->imm) | |
157 | ||
158 | /* | |
159 | * Branch Instructions | |
160 | */ | |
161 | INSN(RJMP, ".%+d", a->imm * 2) | |
162 | INSN(IJMP, "") | |
163 | INSN(EIJMP, "") | |
164 | INSN(JMP, "0x%x", a->imm * 2) | |
165 | INSN(RCALL, ".%+d", a->imm * 2) | |
166 | INSN(ICALL, "") | |
167 | INSN(EICALL, "") | |
168 | INSN(CALL, "0x%x", a->imm * 2) | |
169 | INSN(RET, "") | |
170 | INSN(RETI, "") | |
171 | INSN(CPSE, "r%d, r%d", a->rd, a->rr) | |
172 | INSN(CP, "r%d, r%d", a->rd, a->rr) | |
173 | INSN(CPC, "r%d, r%d", a->rd, a->rr) | |
174 | INSN(CPI, "r%d, %d", a->rd, a->imm) | |
175 | INSN(SBRC, "r%d, %d", a->rr, a->bit) | |
176 | INSN(SBRS, "r%d, %d", a->rr, a->bit) | |
177 | INSN(SBIC, "$%d, %d", a->reg, a->bit) | |
178 | INSN(SBIS, "$%d, %d", a->reg, a->bit) | |
179 | INSN_MNEMONIC(BRBS, brbs[a->bit], ".%+d", a->imm * 2) | |
180 | INSN_MNEMONIC(BRBC, brbc[a->bit], ".%+d", a->imm * 2) | |
181 | ||
182 | /* | |
183 | * Data Transfer Instructions | |
184 | */ | |
185 | INSN(MOV, "r%d, r%d", a->rd, a->rr) | |
186 | INSN(MOVW, "r%d:r%d, r%d:r%d", a->rd + 1, a->rd, a->rr + 1, a->rr) | |
187 | INSN(LDI, "r%d, %d", a->rd, a->imm) | |
188 | INSN(LDS, "r%d, %d", a->rd, a->imm) | |
189 | INSN(LDX1, "r%d, X", a->rd) | |
190 | INSN(LDX2, "r%d, X+", a->rd) | |
191 | INSN(LDX3, "r%d, -X", a->rd) | |
192 | INSN(LDY2, "r%d, Y+", a->rd) | |
193 | INSN(LDY3, "r%d, -Y", a->rd) | |
194 | INSN(LDZ2, "r%d, Z+", a->rd) | |
195 | INSN(LDZ3, "r%d, -Z", a->rd) | |
196 | INSN(LDDY, "r%d, Y+%d", a->rd, a->imm) | |
197 | INSN(LDDZ, "r%d, Z+%d", a->rd, a->imm) | |
198 | INSN(STS, "r%d, %d", a->rd, a->imm) | |
199 | INSN(STX1, "r%d, X", a->rr) | |
200 | INSN(STX2, "r%d, X+", a->rr) | |
201 | INSN(STX3, "r%d, -X", a->rr) | |
202 | INSN(STY2, "r%d, Y+", a->rd) | |
203 | INSN(STY3, "r%d, -Y", a->rd) | |
204 | INSN(STZ2, "r%d, Z+", a->rd) | |
205 | INSN(STZ3, "r%d, -Z", a->rd) | |
206 | INSN(STDY, "r%d, Y+%d", a->rd, a->imm) | |
207 | INSN(STDZ, "r%d, Z+%d", a->rd, a->imm) | |
208 | INSN(LPM1, "") | |
209 | INSN(LPM2, "r%d, Z", a->rd) | |
210 | INSN(LPMX, "r%d, Z+", a->rd) | |
211 | INSN(ELPM1, "") | |
212 | INSN(ELPM2, "r%d, Z", a->rd) | |
213 | INSN(ELPMX, "r%d, Z+", a->rd) | |
214 | INSN(SPM, "") | |
215 | INSN(SPMX, "Z+") | |
216 | INSN(IN, "r%d, $%d", a->rd, a->imm) | |
217 | INSN(OUT, "$%d, r%d", a->imm, a->rd) | |
218 | INSN(PUSH, "r%d", a->rd) | |
219 | INSN(POP, "r%d", a->rd) | |
220 | INSN(XCH, "Z, r%d", a->rd) | |
221 | INSN(LAC, "Z, r%d", a->rd) | |
222 | INSN(LAS, "Z, r%d", a->rd) | |
223 | INSN(LAT, "Z, r%d", a->rd) | |
224 | ||
225 | /* | |
226 | * Bit and Bit-test Instructions | |
227 | */ | |
228 | INSN(LSR, "r%d", a->rd) | |
229 | INSN(ROR, "r%d", a->rd) | |
230 | INSN(ASR, "r%d", a->rd) | |
231 | INSN(SWAP, "r%d", a->rd) | |
232 | INSN(SBI, "$%d, %d", a->reg, a->bit) | |
233 | INSN(CBI, "%d, %d", a->reg, a->bit) | |
234 | INSN(BST, "r%d, %d", a->rd, a->bit) | |
235 | INSN(BLD, "r%d, %d", a->rd, a->bit) | |
236 | INSN_MNEMONIC(BSET, bset[a->bit], "") | |
237 | INSN_MNEMONIC(BCLR, bclr[a->bit], "") | |
238 | ||
239 | /* | |
240 | * MCU Control Instructions | |
241 | */ | |
242 | INSN(BREAK, "") | |
243 | INSN(NOP, "") | |
244 | INSN(SLEEP, "") | |
245 | INSN(WDR, "") |