Add qemu 2.4.0
[kvmfornfv.git] / qemu / disas / moxie.c
1 /* Disassemble moxie instructions.
2    Copyright (c) 2009  Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, see <http://www.gnu.org/licenses/>. */
16
17 #include <stdio.h>
18 #define STATIC_TABLE
19 #define DEFINE_TABLE
20
21 #include "disas/bfd.h"
22
23 static void *stream;
24
25 /* Form 1 instructions come in different flavors:
26
27    Some have no arguments                          (MOXIE_F1_NARG)
28    Some only use the A operand                     (MOXIE_F1_A)
29    Some use A and B registers                      (MOXIE_F1_AB)
30    Some use A and consume a 4 byte immediate value (MOXIE_F1_A4)
31    Some use just a 4 byte immediate value          (MOXIE_F1_4)
32    Some use just a 4 byte memory address           (MOXIE_F1_M)
33    Some use B and an indirect A                    (MOXIE_F1_AiB)
34    Some use A and an indirect B                    (MOXIE_F1_ABi)
35    Some consume a 4 byte immediate value and use X (MOXIE_F1_4A)
36    Some use B and an indirect A plus 4 bytes       (MOXIE_F1_AiB4)
37    Some use A and an indirect B plus 4 bytes       (MOXIE_F1_ABi4)
38
39    Form 2 instructions also come in different flavors:
40
41    Some have no arguments                          (MOXIE_F2_NARG)
42    Some use the A register and an 8-bit value      (MOXIE_F2_A8V)
43
44    Form 3 instructions also come in different flavors:
45
46    Some have no arguments                          (MOXIE_F3_NARG)
47    Some have a 10-bit PC relative operand          (MOXIE_F3_PCREL).  */
48
49 #define MOXIE_F1_NARG 0x100
50 #define MOXIE_F1_A    0x101
51 #define MOXIE_F1_AB   0x102
52 /* #define MOXIE_F1_ABC  0x103 */
53 #define MOXIE_F1_A4   0x104
54 #define MOXIE_F1_4    0x105
55 #define MOXIE_F1_AiB  0x106
56 #define MOXIE_F1_ABi  0x107
57 #define MOXIE_F1_4A   0x108
58 #define MOXIE_F1_AiB4 0x109
59 #define MOXIE_F1_ABi4 0x10a
60 #define MOXIE_F1_M    0x10b
61
62 #define MOXIE_F2_NARG 0x200
63 #define MOXIE_F2_A8V  0x201
64
65 #define MOXIE_F3_NARG  0x300
66 #define MOXIE_F3_PCREL 0x301
67
68 typedef struct moxie_opc_info_t {
69     short         opcode;
70     unsigned      itype;
71     const char *  name;
72 } moxie_opc_info_t;
73
74 extern const moxie_opc_info_t moxie_form1_opc_info[64];
75 extern const moxie_opc_info_t moxie_form2_opc_info[4];
76 extern const moxie_opc_info_t moxie_form3_opc_info[16];
77
78 /* The moxie processor's 16-bit instructions come in two forms:
79
80    FORM 1 instructions start with a 0 bit...
81
82    0oooooooaaaabbbb
83    0              F
84
85    ooooooo - form 1 opcode number
86    aaaa    - operand A
87    bbbb    - operand B
88
89    FORM 2 instructions start with bits "10"...
90
91    10ooaaaavvvvvvvv
92    0              F
93
94    oo       - form 2 opcode number
95    aaaa     - operand A
96    vvvvvvvv - 8-bit immediate value
97
98    FORM 3 instructions start with a bits "11"...
99
100    11oooovvvvvvvvvv
101    0              F
102
103    oooo         - form 3 opcode number
104    vvvvvvvvvv   - 10-bit immediate value.  */
105
106 const moxie_opc_info_t moxie_form1_opc_info[64] =
107     {
108         { 0x00, MOXIE_F1_NARG, "nop" },
109         { 0x01, MOXIE_F1_A4,   "ldi.l" },
110         { 0x02, MOXIE_F1_AB,   "mov" },
111         { 0x03, MOXIE_F1_M,    "jsra" },
112         { 0x04, MOXIE_F1_NARG, "ret" },
113         { 0x05, MOXIE_F1_AB,   "add.l" },
114         { 0x06, MOXIE_F1_AB,   "push" },
115         { 0x07, MOXIE_F1_AB,   "pop" },
116         { 0x08, MOXIE_F1_A4,   "lda.l" },
117         { 0x09, MOXIE_F1_4A,   "sta.l" },
118         { 0x0a, MOXIE_F1_ABi,  "ld.l" },
119         { 0x0b, MOXIE_F1_AiB,  "st.l" },
120         { 0x0c, MOXIE_F1_ABi4, "ldo.l" },
121         { 0x0d, MOXIE_F1_AiB4, "sto.l" },
122         { 0x0e, MOXIE_F1_AB,   "cmp" },
123         { 0x0f, MOXIE_F1_NARG, "bad" },
124         { 0x10, MOXIE_F1_NARG, "bad" },
125         { 0x11, MOXIE_F1_NARG, "bad" },
126         { 0x12, MOXIE_F1_NARG, "bad" },
127         { 0x13, MOXIE_F1_NARG, "bad" },
128         { 0x14, MOXIE_F1_NARG, "bad" },
129         { 0x15, MOXIE_F1_NARG, "bad" },
130         { 0x16, MOXIE_F1_NARG, "bad" },
131         { 0x17, MOXIE_F1_NARG, "bad" },
132         { 0x18, MOXIE_F1_NARG, "bad" },
133         { 0x19, MOXIE_F1_A,    "jsr" },
134         { 0x1a, MOXIE_F1_M,    "jmpa" },
135         { 0x1b, MOXIE_F1_A4,   "ldi.b" },
136         { 0x1c, MOXIE_F1_ABi,  "ld.b" },
137         { 0x1d, MOXIE_F1_A4,   "lda.b" },
138         { 0x1e, MOXIE_F1_AiB,  "st.b" },
139         { 0x1f, MOXIE_F1_4A,   "sta.b" },
140         { 0x20, MOXIE_F1_A4,   "ldi.s" },
141         { 0x21, MOXIE_F1_ABi,  "ld.s" },
142         { 0x22, MOXIE_F1_A4,   "lda.s" },
143         { 0x23, MOXIE_F1_AiB,  "st.s" },
144         { 0x24, MOXIE_F1_4A,   "sta.s" },
145         { 0x25, MOXIE_F1_A,    "jmp" },
146         { 0x26, MOXIE_F1_AB,   "and" },
147         { 0x27, MOXIE_F1_AB,   "lshr" },
148         { 0x28, MOXIE_F1_AB,   "ashl" },
149         { 0x29, MOXIE_F1_AB,   "sub.l" },
150         { 0x2a, MOXIE_F1_AB,   "neg" },
151         { 0x2b, MOXIE_F1_AB,   "or" },
152         { 0x2c, MOXIE_F1_AB,   "not" },
153         { 0x2d, MOXIE_F1_AB,   "ashr" },
154         { 0x2e, MOXIE_F1_AB,   "xor" },
155         { 0x2f, MOXIE_F1_AB,   "mul.l" },
156         { 0x30, MOXIE_F1_4,    "swi" },
157         { 0x31, MOXIE_F1_AB,   "div.l" },
158         { 0x32, MOXIE_F1_AB,   "udiv.l" },
159         { 0x33, MOXIE_F1_AB,   "mod.l" },
160         { 0x34, MOXIE_F1_AB,   "umod.l" },
161         { 0x35, MOXIE_F1_NARG, "brk" },
162         { 0x36, MOXIE_F1_ABi4, "ldo.b" },
163         { 0x37, MOXIE_F1_AiB4, "sto.b" },
164         { 0x38, MOXIE_F1_ABi4, "ldo.s" },
165         { 0x39, MOXIE_F1_AiB4, "sto.s" },
166         { 0x3a, MOXIE_F1_NARG, "bad" },
167         { 0x3b, MOXIE_F1_NARG, "bad" },
168         { 0x3c, MOXIE_F1_NARG, "bad" },
169         { 0x3d, MOXIE_F1_NARG, "bad" },
170         { 0x3e, MOXIE_F1_NARG, "bad" },
171         { 0x3f, MOXIE_F1_NARG, "bad" }
172     };
173
174 const moxie_opc_info_t moxie_form2_opc_info[4] =
175     {
176         { 0x00, MOXIE_F2_A8V,  "inc" },
177         { 0x01, MOXIE_F2_A8V,  "dec" },
178         { 0x02, MOXIE_F2_A8V,  "gsr" },
179         { 0x03, MOXIE_F2_A8V,  "ssr" }
180     };
181
182 const moxie_opc_info_t moxie_form3_opc_info[16] =
183     {
184         { 0x00, MOXIE_F3_PCREL,"beq" },
185         { 0x01, MOXIE_F3_PCREL,"bne" },
186         { 0x02, MOXIE_F3_PCREL,"blt" },
187         { 0x03, MOXIE_F3_PCREL,"bgt" },
188         { 0x04, MOXIE_F3_PCREL,"bltu" },
189         { 0x05, MOXIE_F3_PCREL,"bgtu" },
190         { 0x06, MOXIE_F3_PCREL,"bge" },
191         { 0x07, MOXIE_F3_PCREL,"ble" },
192         { 0x08, MOXIE_F3_PCREL,"bgeu" },
193         { 0x09, MOXIE_F3_PCREL,"bleu" },
194         { 0x0a, MOXIE_F3_NARG, "bad" },
195         { 0x0b, MOXIE_F3_NARG, "bad" },
196         { 0x0c, MOXIE_F3_NARG, "bad" },
197         { 0x0d, MOXIE_F3_NARG, "bad" },
198         { 0x0e, MOXIE_F3_NARG, "bad" },
199         { 0x0f, MOXIE_F3_NARG, "bad" }
200     };
201
202 /* Macros to extract operands from the instruction word.  */
203 #define OP_A(i) ((i >> 4) & 0xf)
204 #define OP_B(i) (i & 0xf)
205 #define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1)
206
207 static const char * reg_names[16] =
208     { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5",
209       "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" };
210
211 int
212 print_insn_moxie(bfd_vma addr, struct disassemble_info * info)
213 {
214     int length = 2;
215     int status;
216     stream = info->stream;
217     const moxie_opc_info_t * opcode;
218     bfd_byte buffer[4];
219     unsigned short iword;
220     fprintf_function fpr = info->fprintf_func;
221
222     if ((status = info->read_memory_func(addr, buffer, 2, info)))
223         goto fail;
224     iword = (bfd_getb16(buffer) >> 16);
225
226     /* Form 1 instructions have the high bit set to 0.  */
227     if ((iword & (1<<15)) == 0) {
228         /* Extract the Form 1 opcode.  */
229         opcode = &moxie_form1_opc_info[iword >> 8];
230         switch (opcode->itype) {
231         case MOXIE_F1_NARG:
232             fpr(stream, "%s", opcode->name);
233             break;
234         case MOXIE_F1_A:
235             fpr(stream, "%s\t%s", opcode->name,
236                 reg_names[OP_A(iword)]);
237             break;
238         case MOXIE_F1_AB:
239             fpr(stream, "%s\t%s, %s", opcode->name,
240                 reg_names[OP_A(iword)],
241                 reg_names[OP_B(iword)]);
242             break;
243         case MOXIE_F1_A4:
244             {
245                 unsigned imm;
246                 if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
247                     goto fail;
248                 imm = bfd_getb32(buffer);
249                 fpr(stream, "%s\t%s, 0x%x", opcode->name,
250                     reg_names[OP_A(iword)], imm);
251                 length = 6;
252             }
253             break;
254         case MOXIE_F1_4:
255             {
256                 unsigned imm;
257                 if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
258                     goto fail;
259                 imm = bfd_getb32(buffer);
260                 fpr(stream, "%s\t0x%x", opcode->name, imm);
261                 length = 6;
262             }
263             break;
264         case MOXIE_F1_M:
265             {
266                 unsigned imm;
267                 if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
268                     goto fail;
269                 imm = bfd_getb32(buffer);
270                 fpr(stream, "%s\t", opcode->name);
271                 info->print_address_func((bfd_vma) imm, info);
272                 length = 6;
273             }
274             break;
275         case MOXIE_F1_AiB:
276             fpr (stream, "%s\t(%s), %s", opcode->name,
277                  reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
278             break;
279         case MOXIE_F1_ABi:
280             fpr(stream, "%s\t%s, (%s)", opcode->name,
281                 reg_names[OP_A(iword)], reg_names[OP_B(iword)]);
282             break;
283         case MOXIE_F1_4A:
284             {
285                 unsigned imm;
286                 if ((status = info->read_memory_func(addr + 2, buffer, 4, info)))
287                     goto fail;
288                 imm = bfd_getb32(buffer);
289                 fpr(stream, "%s\t0x%x, %s",
290                     opcode->name, imm, reg_names[OP_A(iword)]);
291                 length = 6;
292             }
293             break;
294         case MOXIE_F1_AiB4:
295             {
296                 unsigned imm;
297                 if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
298                     goto fail;
299                 imm = bfd_getb32(buffer);
300                 fpr(stream, "%s\t0x%x(%s), %s", opcode->name,
301                     imm,
302                     reg_names[OP_A(iword)],
303                     reg_names[OP_B(iword)]);
304                 length = 6;
305             }
306             break;
307         case MOXIE_F1_ABi4:
308             {
309                 unsigned imm;
310                 if ((status = info->read_memory_func(addr+2, buffer, 4, info)))
311                     goto fail;
312                 imm = bfd_getb32(buffer);
313                 fpr(stream, "%s\t%s, 0x%x(%s)",
314                     opcode->name,
315                     reg_names[OP_A(iword)],
316                     imm,
317                     reg_names[OP_B(iword)]);
318                 length = 6;
319             }
320             break;
321         default:
322             abort();
323         }
324     }
325     else if ((iword & (1<<14)) == 0) {
326         /* Extract the Form 2 opcode.  */
327         opcode = &moxie_form2_opc_info[(iword >> 12) & 3];
328         switch (opcode->itype) {
329         case MOXIE_F2_A8V:
330             fpr(stream, "%s\t%s, 0x%x",
331                 opcode->name,
332                 reg_names[(iword >> 8) & 0xf],
333                 iword & ((1 << 8) - 1));
334             break;
335         case MOXIE_F2_NARG:
336             fpr(stream, "%s", opcode->name);
337             break;
338         default:
339             abort();
340         }
341     } else {
342         /* Extract the Form 3 opcode.  */
343         opcode = &moxie_form3_opc_info[(iword >> 10) & 15];
344         switch (opcode->itype) {
345         case MOXIE_F3_PCREL:
346             fpr(stream, "%s\t", opcode->name);
347             info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2),
348                                      info);
349             break;
350         default:
351             abort();
352         }
353     }
354
355     return length;
356
357  fail:
358     info->memory_error_func(status, addr, info);
359     return -1;
360 }