d10v-dis.c revision 1.1 1 1.1 christos /* Disassemble D10V instructions.
2 1.1 christos Copyright 1996, 1997, 1998, 2000, 2001, 2005, 2007
3 1.1 christos Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos This file is part of the GNU opcodes library.
6 1.1 christos
7 1.1 christos This library is free software; you can redistribute it and/or modify
8 1.1 christos it under the terms of the GNU General Public License as published by
9 1.1 christos the Free Software Foundation; either version 3, or (at your option)
10 1.1 christos any later version.
11 1.1 christos
12 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT
13 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 1.1 christos License for more details.
16 1.1 christos
17 1.1 christos You should have received a copy of the GNU General Public License
18 1.1 christos along with this program; if not, write to the Free Software
19 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 1.1 christos MA 02110-1301, USA. */
21 1.1 christos
22 1.1 christos #include <stdio.h>
23 1.1 christos
24 1.1 christos #include "sysdep.h"
25 1.1 christos #include "opcode/d10v.h"
26 1.1 christos #include "dis-asm.h"
27 1.1 christos
28 1.1 christos /* The PC wraps at 18 bits, except for the segment number,
29 1.1 christos so use this mask to keep the parts we want. */
30 1.1 christos #define PC_MASK 0x0303FFFF
31 1.1 christos
32 1.1 christos static void
33 1.1 christos print_operand (struct d10v_operand *oper,
34 1.1 christos unsigned long insn,
35 1.1 christos struct d10v_opcode *op,
36 1.1 christos bfd_vma memaddr,
37 1.1 christos struct disassemble_info *info)
38 1.1 christos {
39 1.1 christos int num, shift;
40 1.1 christos
41 1.1 christos if (oper->flags == OPERAND_ATMINUS)
42 1.1 christos {
43 1.1 christos (*info->fprintf_func) (info->stream, "@-");
44 1.1 christos return;
45 1.1 christos }
46 1.1 christos if (oper->flags == OPERAND_MINUS)
47 1.1 christos {
48 1.1 christos (*info->fprintf_func) (info->stream, "-");
49 1.1 christos return;
50 1.1 christos }
51 1.1 christos if (oper->flags == OPERAND_PLUS)
52 1.1 christos {
53 1.1 christos (*info->fprintf_func) (info->stream, "+");
54 1.1 christos return;
55 1.1 christos }
56 1.1 christos if (oper->flags == OPERAND_ATSIGN)
57 1.1 christos {
58 1.1 christos (*info->fprintf_func) (info->stream, "@");
59 1.1 christos return;
60 1.1 christos }
61 1.1 christos if (oper->flags == OPERAND_ATPAR)
62 1.1 christos {
63 1.1 christos (*info->fprintf_func) (info->stream, "@(");
64 1.1 christos return;
65 1.1 christos }
66 1.1 christos
67 1.1 christos shift = oper->shift;
68 1.1 christos
69 1.1 christos /* The LONG_L format shifts registers over by 15. */
70 1.1 christos if (op->format == LONG_L && (oper->flags & OPERAND_REG))
71 1.1 christos shift += 15;
72 1.1 christos
73 1.1 christos num = (insn >> shift) & (0x7FFFFFFF >> (31 - oper->bits));
74 1.1 christos
75 1.1 christos if (oper->flags & OPERAND_REG)
76 1.1 christos {
77 1.1 christos int i;
78 1.1 christos int match = 0;
79 1.1 christos
80 1.1 christos num += (oper->flags
81 1.1 christos & (OPERAND_GPR | OPERAND_FFLAG | OPERAND_CFLAG | OPERAND_CONTROL));
82 1.1 christos if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
83 1.1 christos num += num ? OPERAND_ACC1 : OPERAND_ACC0;
84 1.1 christos for (i = 0; i < d10v_reg_name_cnt (); i++)
85 1.1 christos {
86 1.1 christos if (num == (d10v_predefined_registers[i].value & ~ OPERAND_SP))
87 1.1 christos {
88 1.1 christos if (d10v_predefined_registers[i].pname)
89 1.1 christos (*info->fprintf_func) (info->stream, "%s",
90 1.1 christos d10v_predefined_registers[i].pname);
91 1.1 christos else
92 1.1 christos (*info->fprintf_func) (info->stream, "%s",
93 1.1 christos d10v_predefined_registers[i].name);
94 1.1 christos match = 1;
95 1.1 christos break;
96 1.1 christos }
97 1.1 christos }
98 1.1 christos if (match == 0)
99 1.1 christos {
100 1.1 christos /* This would only get executed if a register was not in the
101 1.1 christos register table. */
102 1.1 christos if (oper->flags & (OPERAND_ACC0 | OPERAND_ACC1))
103 1.1 christos (*info->fprintf_func) (info->stream, "a");
104 1.1 christos else if (oper->flags & OPERAND_CONTROL)
105 1.1 christos (*info->fprintf_func) (info->stream, "cr");
106 1.1 christos else if (oper->flags & OPERAND_REG)
107 1.1 christos (*info->fprintf_func) (info->stream, "r");
108 1.1 christos (*info->fprintf_func) (info->stream, "%d", num & REGISTER_MASK);
109 1.1 christos }
110 1.1 christos }
111 1.1 christos else
112 1.1 christos {
113 1.1 christos /* Addresses are right-shifted by 2. */
114 1.1 christos if (oper->flags & OPERAND_ADDR)
115 1.1 christos {
116 1.1 christos long max;
117 1.1 christos int neg = 0;
118 1.1 christos
119 1.1 christos max = (1 << (oper->bits - 1));
120 1.1 christos if (num & max)
121 1.1 christos {
122 1.1 christos num = -num & ((1 << oper->bits) - 1);
123 1.1 christos neg = 1;
124 1.1 christos }
125 1.1 christos num = num << 2;
126 1.1 christos if (info->flags & INSN_HAS_RELOC)
127 1.1 christos (*info->print_address_func) (num & PC_MASK, info);
128 1.1 christos else
129 1.1 christos {
130 1.1 christos if (neg)
131 1.1 christos (*info->print_address_func) ((memaddr - num) & PC_MASK, info);
132 1.1 christos else
133 1.1 christos (*info->print_address_func) ((memaddr + num) & PC_MASK, info);
134 1.1 christos }
135 1.1 christos }
136 1.1 christos else
137 1.1 christos {
138 1.1 christos if (oper->flags & OPERAND_SIGNED)
139 1.1 christos {
140 1.1 christos int max = (1 << (oper->bits - 1));
141 1.1 christos if (num & max)
142 1.1 christos {
143 1.1 christos num = -num & ((1 << oper->bits) - 1);
144 1.1 christos (*info->fprintf_func) (info->stream, "-");
145 1.1 christos }
146 1.1 christos }
147 1.1 christos (*info->fprintf_func) (info->stream, "0x%x", num);
148 1.1 christos }
149 1.1 christos }
150 1.1 christos }
151 1.1 christos
152 1.1 christos static void
153 1.1 christos dis_long (unsigned long insn,
154 1.1 christos bfd_vma memaddr,
155 1.1 christos struct disassemble_info *info)
156 1.1 christos {
157 1.1 christos int i;
158 1.1 christos struct d10v_opcode *op = (struct d10v_opcode *) d10v_opcodes;
159 1.1 christos struct d10v_operand *oper;
160 1.1 christos int need_paren = 0;
161 1.1 christos int match = 0;
162 1.1 christos
163 1.1 christos while (op->name)
164 1.1 christos {
165 1.1 christos if ((op->format & LONG_OPCODE)
166 1.1 christos && ((op->mask & insn) == (unsigned long) op->opcode))
167 1.1 christos {
168 1.1 christos match = 1;
169 1.1 christos (*info->fprintf_func) (info->stream, "%s\t", op->name);
170 1.1 christos
171 1.1 christos for (i = 0; op->operands[i]; i++)
172 1.1 christos {
173 1.1 christos oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
174 1.1 christos if (oper->flags == OPERAND_ATPAR)
175 1.1 christos need_paren = 1;
176 1.1 christos print_operand (oper, insn, op, memaddr, info);
177 1.1 christos if (op->operands[i + 1] && oper->bits
178 1.1 christos && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
179 1.1 christos && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
180 1.1 christos (*info->fprintf_func) (info->stream, ", ");
181 1.1 christos }
182 1.1 christos break;
183 1.1 christos }
184 1.1 christos op++;
185 1.1 christos }
186 1.1 christos
187 1.1 christos if (!match)
188 1.1 christos (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
189 1.1 christos
190 1.1 christos if (need_paren)
191 1.1 christos (*info->fprintf_func) (info->stream, ")");
192 1.1 christos }
193 1.1 christos
194 1.1 christos static void
195 1.1 christos dis_2_short (unsigned long insn,
196 1.1 christos bfd_vma memaddr,
197 1.1 christos struct disassemble_info *info,
198 1.1 christos int order)
199 1.1 christos {
200 1.1 christos int i, j;
201 1.1 christos unsigned int ins[2];
202 1.1 christos struct d10v_opcode *op;
203 1.1 christos int match, num_match = 0;
204 1.1 christos struct d10v_operand *oper;
205 1.1 christos int need_paren = 0;
206 1.1 christos
207 1.1 christos ins[0] = (insn & 0x3FFFFFFF) >> 15;
208 1.1 christos ins[1] = insn & 0x00007FFF;
209 1.1 christos
210 1.1 christos for (j = 0; j < 2; j++)
211 1.1 christos {
212 1.1 christos op = (struct d10v_opcode *) d10v_opcodes;
213 1.1 christos match = 0;
214 1.1 christos while (op->name)
215 1.1 christos {
216 1.1 christos if ((op->format & SHORT_OPCODE)
217 1.1 christos && ((((unsigned int) op->mask) & ins[j])
218 1.1 christos == (unsigned int) op->opcode))
219 1.1 christos {
220 1.1 christos (*info->fprintf_func) (info->stream, "%s\t", op->name);
221 1.1 christos for (i = 0; op->operands[i]; i++)
222 1.1 christos {
223 1.1 christos oper = (struct d10v_operand *) &d10v_operands[op->operands[i]];
224 1.1 christos if (oper->flags == OPERAND_ATPAR)
225 1.1 christos need_paren = 1;
226 1.1 christos print_operand (oper, ins[j], op, memaddr, info);
227 1.1 christos if (op->operands[i + 1] && oper->bits
228 1.1 christos && d10v_operands[op->operands[i + 1]].flags != OPERAND_PLUS
229 1.1 christos && d10v_operands[op->operands[i + 1]].flags != OPERAND_MINUS)
230 1.1 christos (*info->fprintf_func) (info->stream, ", ");
231 1.1 christos }
232 1.1 christos match = 1;
233 1.1 christos num_match++;
234 1.1 christos break;
235 1.1 christos }
236 1.1 christos op++;
237 1.1 christos }
238 1.1 christos if (!match)
239 1.1 christos (*info->fprintf_func) (info->stream, "unknown");
240 1.1 christos
241 1.1 christos switch (order)
242 1.1 christos {
243 1.1 christos case 0:
244 1.1 christos (*info->fprintf_func) (info->stream, "\t->\t");
245 1.1 christos order = -1;
246 1.1 christos break;
247 1.1 christos case 1:
248 1.1 christos (*info->fprintf_func) (info->stream, "\t<-\t");
249 1.1 christos order = -1;
250 1.1 christos break;
251 1.1 christos case 2:
252 1.1 christos (*info->fprintf_func) (info->stream, "\t||\t");
253 1.1 christos order = -1;
254 1.1 christos break;
255 1.1 christos default:
256 1.1 christos break;
257 1.1 christos }
258 1.1 christos }
259 1.1 christos
260 1.1 christos if (num_match == 0)
261 1.1 christos (*info->fprintf_func) (info->stream, ".long\t0x%08lx", insn);
262 1.1 christos
263 1.1 christos if (need_paren)
264 1.1 christos (*info->fprintf_func) (info->stream, ")");
265 1.1 christos }
266 1.1 christos
267 1.1 christos int
268 1.1 christos print_insn_d10v (bfd_vma memaddr, struct disassemble_info *info)
269 1.1 christos {
270 1.1 christos int status;
271 1.1 christos bfd_byte buffer[4];
272 1.1 christos unsigned long insn;
273 1.1 christos
274 1.1 christos status = (*info->read_memory_func) (memaddr, buffer, 4, info);
275 1.1 christos if (status != 0)
276 1.1 christos {
277 1.1 christos (*info->memory_error_func) (status, memaddr, info);
278 1.1 christos return -1;
279 1.1 christos }
280 1.1 christos insn = bfd_getb32 (buffer);
281 1.1 christos
282 1.1 christos status = insn & FM11;
283 1.1 christos switch (status)
284 1.1 christos {
285 1.1 christos case 0:
286 1.1 christos dis_2_short (insn, memaddr, info, 2);
287 1.1 christos break;
288 1.1 christos case FM01:
289 1.1 christos dis_2_short (insn, memaddr, info, 0);
290 1.1 christos break;
291 1.1 christos case FM10:
292 1.1 christos dis_2_short (insn, memaddr, info, 1);
293 1.1 christos break;
294 1.1 christos case FM11:
295 1.1 christos dis_long (insn, memaddr, info);
296 1.1 christos break;
297 1.1 christos }
298 1.1 christos return 4;
299 1.1 christos }
300