]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/v850-dis.c
This commit was generated by cvs2svn to track changes on a CVS vendor
[thirdparty/binutils-gdb.git] / opcodes / v850-dis.c
1 /* Disassemble V850 instructions.
2 Copyright 1996, 1997, 1998, 2000, 2001 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, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18
19 #include <stdio.h>
20
21 #include "sysdep.h"
22 #include "opcode/v850.h"
23 #include "dis-asm.h"
24 #include "opintl.h"
25
26 static const char *const v850_reg_names[] =
27 { "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
28 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
29 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
30 "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
31
32 static const char *const v850_sreg_names[] =
33 { "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7",
34 "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
35 "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23",
36 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31",
37 "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
38 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
39
40 static const char *const v850_cc_names[] =
41 { "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
42 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
43
44 static int disassemble
45 PARAMS ((bfd_vma, struct disassemble_info *, unsigned long));
46
47 static int
48 disassemble (memaddr, info, insn)
49 bfd_vma memaddr;
50 struct disassemble_info *info;
51 unsigned long insn;
52 {
53 struct v850_opcode * op = (struct v850_opcode *)v850_opcodes;
54 const struct v850_operand * operand;
55 int match = 0;
56 int short_op = ((insn & 0x0600) != 0x0600);
57 int bytes_read;
58 int target_processor;
59
60 /* Special case: 32 bit MOV */
61 if ((insn & 0xffe0) == 0x0620)
62 short_op = true;
63
64 bytes_read = short_op ? 2 : 4;
65
66 /* If this is a two byte insn, then mask off the high bits. */
67 if (short_op)
68 insn &= 0xffff;
69
70 switch (info->mach)
71 {
72 case 0:
73 default:
74 target_processor = PROCESSOR_V850;
75 break;
76
77 case bfd_mach_v850e:
78 target_processor = PROCESSOR_V850E;
79 break;
80
81 case bfd_mach_v850ea:
82 target_processor = PROCESSOR_V850EA;
83 break;
84 }
85
86 /* Find the opcode. */
87 while (op->name)
88 {
89 if ((op->mask & insn) == op->opcode
90 && (op->processors & target_processor))
91 {
92 const unsigned char * opindex_ptr;
93 unsigned int opnum;
94 unsigned int memop;
95
96 match = 1;
97 (*info->fprintf_func) (info->stream, "%s\t", op->name);
98 /*fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );*/
99
100 memop = op->memop;
101 /* Now print the operands.
102
103 MEMOP is the operand number at which a memory
104 address specification starts, or zero if this
105 instruction has no memory addresses.
106
107 A memory address is always two arguments.
108
109 This information allows us to determine when to
110 insert commas into the output stream as well as
111 when to insert disp[reg] expressions onto the
112 output stream. */
113
114 for (opindex_ptr = op->operands, opnum = 1;
115 *opindex_ptr != 0;
116 opindex_ptr++, opnum++)
117 {
118 long value;
119 int flag;
120 int status;
121 bfd_byte buffer[ 4 ];
122
123 operand = &v850_operands[*opindex_ptr];
124
125 if (operand->extract)
126 value = (operand->extract) (insn, 0);
127 else
128 {
129 if (operand->bits == -1)
130 value = (insn & operand->shift);
131 else
132 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
133
134 if (operand->flags & V850_OPERAND_SIGNED)
135 value = ((long)(value << (32 - operand->bits))
136 >> (32 - operand->bits));
137 }
138
139 /* The first operand is always output without any
140 special handling.
141
142 For the following arguments:
143
144 If memop && opnum == memop + 1, then we need '[' since
145 we're about to output the register used in a memory
146 reference.
147
148 If memop && opnum == memop + 2, then we need ']' since
149 we just finished the register in a memory reference. We
150 also need a ',' before this operand.
151
152 Else we just need a comma.
153
154 We may need to output a trailing ']' if the last operand
155 in an instruction is the register for a memory address.
156
157 The exception (and there's always an exception) is the
158 "jmp" insn which needs square brackets around it's only
159 register argument. */
160
161 if (memop && opnum == memop + 1) info->fprintf_func (info->stream, "[");
162 else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],");
163 else if (memop == 1 && opnum == 1
164 && (operand->flags & V850_OPERAND_REG))
165 info->fprintf_func (info->stream, "[");
166 else if (opnum > 1) info->fprintf_func (info->stream, ", ");
167
168 /* extract the flags, ignorng ones which do not effect disassembly output. */
169 flag = operand->flags;
170 flag &= ~ V850_OPERAND_SIGNED;
171 flag &= ~ V850_OPERAND_RELAX;
172 flag &= - flag;
173
174 switch (flag)
175 {
176 case V850_OPERAND_REG: info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
177 case V850_OPERAND_SRG: info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
178 case V850_OPERAND_CC: info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
179 case V850_OPERAND_EP: info->fprintf_func (info->stream, "ep"); break;
180 default: info->fprintf_func (info->stream, "%d", value); break;
181 case V850_OPERAND_DISP:
182 {
183 bfd_vma addr = value + memaddr;
184
185 /* On the v850 the top 8 bits of an address are used by an overlay manager.
186 Thus it may happen that when we are looking for a symbol to match
187 against an address with some of its top bits set, the search fails to
188 turn up an exact match. In this case we try to find an exact match
189 against a symbol in the lower address space, and if we find one, we
190 use that address. We only do this for JARL instructions however, as
191 we do not want to misinterpret branch instructions. */
192 if (operand->bits == 22)
193 {
194 if ( ! info->symbol_at_address_func (addr, info)
195 && ((addr & 0xFF000000) != 0)
196 && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
197 {
198 addr &= 0x00FFFFFF;
199 }
200 }
201 info->print_address_func (addr, info);
202 break;
203 }
204
205 case V850E_PUSH_POP:
206 {
207 static int list12_regs[32] = { 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
208 static int list18_h_regs[32] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
209 static int list18_l_regs[32] = { 3, 2, 1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 14, 15, 13, 12, 7, 6, 5, 4, 11, 10, 9, 8 };
210 int * regs;
211 int i;
212 unsigned long int mask = 0;
213 int pc = false;
214 int sr = false;
215
216
217 switch (operand->shift)
218 {
219 case 0xffe00001: regs = list12_regs; break;
220 case 0xfff8000f: regs = list18_h_regs; break;
221 case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break; /* Do not include magic bit */
222 default:
223 /* xgettext:c-format */
224 fprintf (stderr, _("unknown operand shift: %x\n"), operand->shift );
225 abort();
226 }
227
228 for (i = 0; i < 32; i++)
229 {
230 if (value & (1 << i))
231 {
232 switch (regs[ i ])
233 {
234 default: mask |= (1 << regs[ i ]); break;
235 /* xgettext:c-format */
236 case 0: fprintf (stderr, _("unknown pop reg: %d\n"), i ); abort();
237 case -1: pc = true; break;
238 case -2: sr = true; break;
239 }
240 }
241 }
242
243 info->fprintf_func (info->stream, "{");
244
245 if (mask || pc || sr)
246 {
247 if (mask)
248 {
249 unsigned int bit;
250 int shown_one = false;
251
252 for (bit = 0; bit < 32; bit++)
253 if (mask & (1 << bit))
254 {
255 unsigned long int first = bit;
256 unsigned long int last;
257
258 if (shown_one)
259 info->fprintf_func (info->stream, ", ");
260 else
261 shown_one = true;
262
263 info->fprintf_func (info->stream, v850_reg_names[first]);
264
265 for (bit++; bit < 32; bit++)
266 if ((mask & (1 << bit)) == 0)
267 break;
268
269 last = bit;
270
271 if (last > first + 1)
272 {
273 info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]);
274 }
275 }
276 }
277
278 if (pc)
279 info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
280 if (sr)
281 info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
282 }
283
284 info->fprintf_func (info->stream, "}");
285 }
286 break;
287
288 case V850E_IMMEDIATE16:
289 status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
290 if (status == 0)
291 {
292 bytes_read += 2;
293 value = bfd_getl16 (buffer);
294
295 /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16. */
296 if ((insn & 0x001fffc0) == 0x00130780)
297 value <<= 16;
298
299 info->fprintf_func (info->stream, "0x%x", value);
300 }
301 else
302 {
303 info->memory_error_func (status, memaddr + bytes_read, info);
304 }
305 break;
306
307 case V850E_IMMEDIATE32:
308 status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
309 if (status == 0)
310 {
311 bytes_read += 4;
312 value = bfd_getl32 (buffer);
313 info->fprintf_func (info->stream, "0x%lx", value);
314 }
315 else
316 {
317 info->memory_error_func (status, memaddr + bytes_read, info);
318 }
319 break;
320 }
321
322 /* Handle jmp correctly. */
323 if (memop == 1 && opnum == 1
324 && ((operand->flags & V850_OPERAND_REG) != 0))
325 (*info->fprintf_func) (info->stream, "]");
326 }
327
328 /* Close any square bracket we left open. */
329 if (memop && opnum == memop + 2)
330 (*info->fprintf_func) (info->stream, "]");
331
332 /* All done. */
333 break;
334 }
335 op++;
336 }
337
338 if (!match)
339 {
340 if (short_op)
341 info->fprintf_func (info->stream, ".short\t0x%04x", insn);
342 else
343 info->fprintf_func (info->stream, ".long\t0x%08x", insn);
344 }
345
346 return bytes_read;
347 }
348
349 int
350 print_insn_v850 (memaddr, info)
351 bfd_vma memaddr;
352 struct disassemble_info * info;
353 {
354 int status;
355 bfd_byte buffer[ 4 ];
356 unsigned long insn = 0;
357
358 /* First figure out how big the opcode is. */
359
360 status = info->read_memory_func (memaddr, buffer, 2, info);
361 if (status == 0)
362 {
363 insn = bfd_getl16 (buffer);
364
365 if ( (insn & 0x0600) == 0x0600
366 && (insn & 0xffe0) != 0x0620)
367 {
368 /* If this is a 4 byte insn, read 4 bytes of stuff. */
369 status = info->read_memory_func (memaddr, buffer, 4, info);
370
371 if (status == 0)
372 insn = bfd_getl32 (buffer);
373 }
374 }
375
376 if (status != 0)
377 {
378 info->memory_error_func (status, memaddr, info);
379 return -1;
380 }
381
382 /* Make sure we tell our caller how many bytes we consumed. */
383 return disassemble (memaddr, info, insn);
384 }