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