]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - opcodes/v850-dis.c
* v850-dis.c (disassemble): Remove bfd_mach_v850ea case.
[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
82 /* Find the opcode. */
83 while (op->name)
84 {
85 if ((op->mask & insn) == op->opcode
86 && (op->processors & target_processor))
87 {
88 const unsigned char * opindex_ptr;
89 unsigned int opnum;
90 unsigned int memop;
91
92 match = 1;
93 (*info->fprintf_func) (info->stream, "%s\t", op->name);
94 /*fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );*/
95
96 memop = op->memop;
97 /* Now print the operands.
98
99 MEMOP is the operand number at which a memory
100 address specification starts, or zero if this
101 instruction has no memory addresses.
102
103 A memory address is always two arguments.
104
105 This information allows us to determine when to
106 insert commas into the output stream as well as
107 when to insert disp[reg] expressions onto the
108 output stream. */
109
110 for (opindex_ptr = op->operands, opnum = 1;
111 *opindex_ptr != 0;
112 opindex_ptr++, opnum++)
113 {
114 long value;
115 int flag;
116 int status;
117 bfd_byte buffer[ 4 ];
118
119 operand = &v850_operands[*opindex_ptr];
120
121 if (operand->extract)
122 value = (operand->extract) (insn, 0);
123 else
124 {
125 if (operand->bits == -1)
126 value = (insn & operand->shift);
127 else
128 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
129
130 if (operand->flags & V850_OPERAND_SIGNED)
131 value = ((long)(value << (32 - operand->bits))
132 >> (32 - operand->bits));
133 }
134
135 /* The first operand is always output without any
136 special handling.
137
138 For the following arguments:
139
140 If memop && opnum == memop + 1, then we need '[' since
141 we're about to output the register used in a memory
142 reference.
143
144 If memop && opnum == memop + 2, then we need ']' since
145 we just finished the register in a memory reference. We
146 also need a ',' before this operand.
147
148 Else we just need a comma.
149
150 We may need to output a trailing ']' if the last operand
151 in an instruction is the register for a memory address.
152
153 The exception (and there's always an exception) is the
154 "jmp" insn which needs square brackets around it's only
155 register argument. */
156
157 if (memop && opnum == memop + 1) info->fprintf_func (info->stream, "[");
158 else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],");
159 else if (memop == 1 && opnum == 1
160 && (operand->flags & V850_OPERAND_REG))
161 info->fprintf_func (info->stream, "[");
162 else if (opnum > 1) info->fprintf_func (info->stream, ", ");
163
164 /* extract the flags, ignorng ones which do not effect disassembly output. */
165 flag = operand->flags;
166 flag &= ~ V850_OPERAND_SIGNED;
167 flag &= ~ V850_OPERAND_RELAX;
168 flag &= - flag;
169
170 switch (flag)
171 {
172 case V850_OPERAND_REG: info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
173 case V850_OPERAND_SRG: info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
174 case V850_OPERAND_CC: info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
175 case V850_OPERAND_EP: info->fprintf_func (info->stream, "ep"); break;
176 default: info->fprintf_func (info->stream, "%d", value); break;
177 case V850_OPERAND_DISP:
178 {
179 bfd_vma addr = value + memaddr;
180
181 /* On the v850 the top 8 bits of an address are used by an overlay manager.
182 Thus it may happen that when we are looking for a symbol to match
183 against an address with some of its top bits set, the search fails to
184 turn up an exact match. In this case we try to find an exact match
185 against a symbol in the lower address space, and if we find one, we
186 use that address. We only do this for JARL instructions however, as
187 we do not want to misinterpret branch instructions. */
188 if (operand->bits == 22)
189 {
190 if ( ! info->symbol_at_address_func (addr, info)
191 && ((addr & 0xFF000000) != 0)
192 && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
193 {
194 addr &= 0x00FFFFFF;
195 }
196 }
197 info->print_address_func (addr, info);
198 break;
199 }
200
201 case V850E_PUSH_POP:
202 {
203 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 };
204 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 };
205 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 };
206 int * regs;
207 int i;
208 unsigned long int mask = 0;
209 int pc = false;
210 int sr = false;
211
212
213 switch (operand->shift)
214 {
215 case 0xffe00001: regs = list12_regs; break;
216 case 0xfff8000f: regs = list18_h_regs; break;
217 case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break; /* Do not include magic bit */
218 default:
219 /* xgettext:c-format */
220 fprintf (stderr, _("unknown operand shift: %x\n"), operand->shift );
221 abort();
222 }
223
224 for (i = 0; i < 32; i++)
225 {
226 if (value & (1 << i))
227 {
228 switch (regs[ i ])
229 {
230 default: mask |= (1 << regs[ i ]); break;
231 /* xgettext:c-format */
232 case 0: fprintf (stderr, _("unknown pop reg: %d\n"), i ); abort();
233 case -1: pc = true; break;
234 case -2: sr = true; break;
235 }
236 }
237 }
238
239 info->fprintf_func (info->stream, "{");
240
241 if (mask || pc || sr)
242 {
243 if (mask)
244 {
245 unsigned int bit;
246 int shown_one = false;
247
248 for (bit = 0; bit < 32; bit++)
249 if (mask & (1 << bit))
250 {
251 unsigned long int first = bit;
252 unsigned long int last;
253
254 if (shown_one)
255 info->fprintf_func (info->stream, ", ");
256 else
257 shown_one = true;
258
259 info->fprintf_func (info->stream, v850_reg_names[first]);
260
261 for (bit++; bit < 32; bit++)
262 if ((mask & (1 << bit)) == 0)
263 break;
264
265 last = bit;
266
267 if (last > first + 1)
268 {
269 info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]);
270 }
271 }
272 }
273
274 if (pc)
275 info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
276 if (sr)
277 info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
278 }
279
280 info->fprintf_func (info->stream, "}");
281 }
282 break;
283
284 case V850E_IMMEDIATE16:
285 status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
286 if (status == 0)
287 {
288 bytes_read += 2;
289 value = bfd_getl16 (buffer);
290
291 /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16. */
292 if ((insn & 0x001fffc0) == 0x00130780)
293 value <<= 16;
294
295 info->fprintf_func (info->stream, "0x%x", value);
296 }
297 else
298 {
299 info->memory_error_func (status, memaddr + bytes_read, info);
300 }
301 break;
302
303 case V850E_IMMEDIATE32:
304 status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
305 if (status == 0)
306 {
307 bytes_read += 4;
308 value = bfd_getl32 (buffer);
309 info->fprintf_func (info->stream, "0x%lx", value);
310 }
311 else
312 {
313 info->memory_error_func (status, memaddr + bytes_read, info);
314 }
315 break;
316 }
317
318 /* Handle jmp correctly. */
319 if (memop == 1 && opnum == 1
320 && ((operand->flags & V850_OPERAND_REG) != 0))
321 (*info->fprintf_func) (info->stream, "]");
322 }
323
324 /* Close any square bracket we left open. */
325 if (memop && opnum == memop + 2)
326 (*info->fprintf_func) (info->stream, "]");
327
328 /* All done. */
329 break;
330 }
331 op++;
332 }
333
334 if (!match)
335 {
336 if (short_op)
337 info->fprintf_func (info->stream, ".short\t0x%04x", insn);
338 else
339 info->fprintf_func (info->stream, ".long\t0x%08x", insn);
340 }
341
342 return bytes_read;
343 }
344
345 int
346 print_insn_v850 (memaddr, info)
347 bfd_vma memaddr;
348 struct disassemble_info * info;
349 {
350 int status;
351 bfd_byte buffer[ 4 ];
352 unsigned long insn = 0;
353
354 /* First figure out how big the opcode is. */
355
356 status = info->read_memory_func (memaddr, buffer, 2, info);
357 if (status == 0)
358 {
359 insn = bfd_getl16 (buffer);
360
361 if ( (insn & 0x0600) == 0x0600
362 && (insn & 0xffe0) != 0x0620)
363 {
364 /* If this is a 4 byte insn, read 4 bytes of stuff. */
365 status = info->read_memory_func (memaddr, buffer, 4, info);
366
367 if (status == 0)
368 insn = bfd_getl32 (buffer);
369 }
370 }
371
372 if (status != 0)
373 {
374 info->memory_error_func (status, memaddr, info);
375 return -1;
376 }
377
378 /* Make sure we tell our caller how many bytes we consumed. */
379 return disassemble (memaddr, info, insn);
380 }