Kaveh Ghazi's printf format attribute checking patch.
[deliverable/binutils-gdb.git] / opcodes / v850-dis.c
CommitLineData
252b5132 1/* Disassemble V850 instructions.
47b0e7ad 2 Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005
b34976b6 3 Free Software Foundation, Inc.
252b5132 4
8ad30312
NC
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
252b5132 9
8ad30312
NC
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
252b5132 14
8ad30312
NC
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
47b0e7ad
NC
17 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
18 MA 02110-1301, USA. */
252b5132
RH
19
20
21#include <stdio.h>
22
0d8dfecf 23#include "sysdep.h"
47b0e7ad 24#include "opcode/v850.h"
252b5132
RH
25#include "dis-asm.h"
26#include "opintl.h"
27
28static const char *const v850_reg_names[] =
47b0e7ad
NC
29{ "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
30 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
31 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
252b5132
RH
32 "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
33
34static const char *const v850_sreg_names[] =
47b0e7ad 35{ "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7",
252b5132 36 "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
47b0e7ad 37 "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23",
252b5132 38 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31",
47b0e7ad 39 "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
252b5132
RH
40 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
41
42static const char *const v850_cc_names[] =
47b0e7ad 43{ "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
252b5132
RH
44 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
45
46static int
47b0e7ad
NC
47disassemble (bfd_vma memaddr,
48 struct disassemble_info * info,
49 unsigned long insn)
252b5132 50{
47b0e7ad
NC
51 struct v850_opcode * op = (struct v850_opcode *) v850_opcodes;
52 const struct v850_operand * operand;
b34976b6
AM
53 int match = 0;
54 int short_op = ((insn & 0x0600) != 0x0600);
55 int bytes_read;
56 int target_processor;
47b0e7ad
NC
57
58 /* Special case: 32 bit MOV. */
252b5132 59 if ((insn & 0xffe0) == 0x0620)
b34976b6 60 short_op = 1;
47b0e7ad 61
252b5132 62 bytes_read = short_op ? 2 : 4;
47b0e7ad
NC
63
64 /* If this is a two byte insn, then mask off the high bits. */
252b5132
RH
65 if (short_op)
66 insn &= 0xffff;
67
68 switch (info->mach)
69 {
70 case 0:
71 default:
72 target_processor = PROCESSOR_V850;
73 break;
74
75 case bfd_mach_v850e:
76 target_processor = PROCESSOR_V850E;
77 break;
8ad30312
NC
78
79 case bfd_mach_v850e1:
80 target_processor = PROCESSOR_V850E1;
81 break;
252b5132 82 }
47b0e7ad 83
252b5132
RH
84 /* Find the opcode. */
85 while (op->name)
86 {
87 if ((op->mask & insn) == op->opcode
88 && (op->processors & target_processor))
89 {
b34976b6
AM
90 const unsigned char *opindex_ptr;
91 unsigned int opnum;
92 unsigned int memop;
252b5132
RH
93
94 match = 1;
95 (*info->fprintf_func) (info->stream, "%s\t", op->name);
252b5132
RH
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. */
47b0e7ad 110
252b5132
RH
111 for (opindex_ptr = op->operands, opnum = 1;
112 *opindex_ptr != 0;
113 opindex_ptr++, opnum++)
114 {
b34976b6
AM
115 long value;
116 int flag;
117 int status;
118 bfd_byte buffer[4];
47b0e7ad 119
252b5132 120 operand = &v850_operands[*opindex_ptr];
47b0e7ad 121
252b5132
RH
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
47b0e7ad 152 in an instruction is the register for a memory address.
252b5132
RH
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
47b0e7ad
NC
158 if (memop && opnum == memop + 1)
159 info->fprintf_func (info->stream, "[");
160 else if (memop && opnum == memop + 2)
161 info->fprintf_func (info->stream, "],");
162 else if (memop == 1 && opnum == 1
163 && (operand->flags & V850_OPERAND_REG))
164 info->fprintf_func (info->stream, "[");
165 else if (opnum > 1)
166 info->fprintf_func (info->stream, ", ");
167
168 /* Extract the flags, ignorng ones which
169 do not effect disassembly output. */
252b5132
RH
170 flag = operand->flags;
171 flag &= ~ V850_OPERAND_SIGNED;
172 flag &= ~ V850_OPERAND_RELAX;
173 flag &= - flag;
47b0e7ad 174
252b5132
RH
175 switch (flag)
176 {
47b0e7ad
NC
177 case V850_OPERAND_REG:
178 info->fprintf_func (info->stream, "%s", v850_reg_names[value]);
179 break;
180 case V850_OPERAND_SRG:
181 info->fprintf_func (info->stream, "%s", v850_sreg_names[value]);
182 break;
183 case V850_OPERAND_CC:
184 info->fprintf_func (info->stream, "%s", v850_cc_names[value]);
185 break;
186 case V850_OPERAND_EP:
187 info->fprintf_func (info->stream, "ep");
188 break;
189 default:
0fd3a477 190 info->fprintf_func (info->stream, "%ld", value);
47b0e7ad 191 break;
252b5132
RH
192 case V850_OPERAND_DISP:
193 {
194 bfd_vma addr = value + memaddr;
47b0e7ad
NC
195
196 /* On the v850 the top 8 bits of an address are used by an
197 overlay manager. Thus it may happen that when we are
198 looking for a symbol to match against an address with
199 some of its top bits set, the search fails to turn up an
200 exact match. In this case we try to find an exact match
201 against a symbol in the lower address space, and if we
202 find one, we use that address. We only do this for
203 JARL instructions however, as we do not want to
204 misinterpret branch instructions. */
252b5132
RH
205 if (operand->bits == 22)
206 {
207 if ( ! info->symbol_at_address_func (addr, info)
208 && ((addr & 0xFF000000) != 0)
209 && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
47b0e7ad 210 addr &= 0x00FFFFFF;
252b5132
RH
211 }
212 info->print_address_func (addr, info);
213 break;
214 }
47b0e7ad 215
252b5132
RH
216 case V850E_PUSH_POP:
217 {
218 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 };
219 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 };
220 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 };
b34976b6
AM
221 int *regs;
222 int i;
252b5132 223 unsigned long int mask = 0;
b34976b6
AM
224 int pc = 0;
225 int sr = 0;
47b0e7ad 226
252b5132
RH
227 switch (operand->shift)
228 {
229 case 0xffe00001: regs = list12_regs; break;
230 case 0xfff8000f: regs = list18_h_regs; break;
47b0e7ad
NC
231 case 0xfff8001f:
232 regs = list18_l_regs;
233 value &= ~0x10; /* Do not include magic bit. */
234 break;
252b5132
RH
235 default:
236 /* xgettext:c-format */
47b0e7ad
NC
237 fprintf (stderr, _("unknown operand shift: %x\n"),
238 operand->shift);
239 abort ();
252b5132
RH
240 }
241
242 for (i = 0; i < 32; i++)
243 {
244 if (value & (1 << i))
245 {
246 switch (regs[ i ])
247 {
248 default: mask |= (1 << regs[ i ]); break;
249 /* xgettext:c-format */
47b0e7ad
NC
250 case 0:
251 fprintf (stderr, _("unknown pop reg: %d\n"), i );
252 abort ();
b34976b6
AM
253 case -1: pc = 1; break;
254 case -2: sr = 1; break;
252b5132
RH
255 }
256 }
257 }
258
259 info->fprintf_func (info->stream, "{");
47b0e7ad 260
252b5132
RH
261 if (mask || pc || sr)
262 {
263 if (mask)
264 {
265 unsigned int bit;
b34976b6 266 int shown_one = 0;
47b0e7ad 267
252b5132
RH
268 for (bit = 0; bit < 32; bit++)
269 if (mask & (1 << bit))
270 {
271 unsigned long int first = bit;
272 unsigned long int last;
273
274 if (shown_one)
275 info->fprintf_func (info->stream, ", ");
276 else
b34976b6 277 shown_one = 1;
47b0e7ad
NC
278
279 info->fprintf_func (info->stream,
280 v850_reg_names[first]);
281
252b5132
RH
282 for (bit++; bit < 32; bit++)
283 if ((mask & (1 << bit)) == 0)
284 break;
285
286 last = bit;
287
288 if (last > first + 1)
47b0e7ad
NC
289 info->fprintf_func (info->stream, " - %s",
290 v850_reg_names[last - 1]);
252b5132
RH
291 }
292 }
47b0e7ad 293
252b5132
RH
294 if (pc)
295 info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
296 if (sr)
297 info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
298 }
47b0e7ad 299
252b5132
RH
300 info->fprintf_func (info->stream, "}");
301 }
302 break;
47b0e7ad 303
252b5132 304 case V850E_IMMEDIATE16:
47b0e7ad
NC
305 status = info->read_memory_func (memaddr + bytes_read,
306 buffer, 2, info);
252b5132
RH
307 if (status == 0)
308 {
309 bytes_read += 2;
310 value = bfd_getl16 (buffer);
311
47b0e7ad
NC
312 /* If this is a DISPOSE instruction with ff
313 set to 0x10, then shift value up by 16. */
252b5132
RH
314 if ((insn & 0x001fffc0) == 0x00130780)
315 value <<= 16;
316
0fd3a477 317 info->fprintf_func (info->stream, "0x%lx", value);
252b5132
RH
318 }
319 else
47b0e7ad
NC
320 info->memory_error_func (status, memaddr + bytes_read,
321 info);
252b5132 322 break;
47b0e7ad 323
252b5132 324 case V850E_IMMEDIATE32:
47b0e7ad
NC
325 status = info->read_memory_func (memaddr + bytes_read,
326 buffer, 4, info);
252b5132
RH
327 if (status == 0)
328 {
329 bytes_read += 4;
330 value = bfd_getl32 (buffer);
331 info->fprintf_func (info->stream, "0x%lx", value);
332 }
333 else
47b0e7ad
NC
334 info->memory_error_func (status, memaddr + bytes_read,
335 info);
252b5132 336 break;
47b0e7ad 337 }
252b5132
RH
338
339 /* Handle jmp correctly. */
340 if (memop == 1 && opnum == 1
341 && ((operand->flags & V850_OPERAND_REG) != 0))
342 (*info->fprintf_func) (info->stream, "]");
343 }
344
345 /* Close any square bracket we left open. */
346 if (memop && opnum == memop + 2)
347 (*info->fprintf_func) (info->stream, "]");
348
349 /* All done. */
350 break;
351 }
352 op++;
353 }
354
355 if (!match)
356 {
357 if (short_op)
0fd3a477 358 info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
252b5132 359 else
0fd3a477 360 info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
252b5132
RH
361 }
362
363 return bytes_read;
364}
365
47b0e7ad
NC
366int
367print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
252b5132 368{
b34976b6
AM
369 int status;
370 bfd_byte buffer[4];
252b5132
RH
371 unsigned long insn = 0;
372
373 /* First figure out how big the opcode is. */
252b5132
RH
374 status = info->read_memory_func (memaddr, buffer, 2, info);
375 if (status == 0)
376 {
377 insn = bfd_getl16 (buffer);
47b0e7ad 378
252b5132
RH
379 if ( (insn & 0x0600) == 0x0600
380 && (insn & 0xffe0) != 0x0620)
381 {
382 /* If this is a 4 byte insn, read 4 bytes of stuff. */
383 status = info->read_memory_func (memaddr, buffer, 4, info);
384
385 if (status == 0)
386 insn = bfd_getl32 (buffer);
387 }
388 }
47b0e7ad 389
252b5132
RH
390 if (status != 0)
391 {
392 info->memory_error_func (status, memaddr, info);
393 return -1;
394 }
395
396 /* Make sure we tell our caller how many bytes we consumed. */
397 return disassemble (memaddr, info, insn);
398}
This page took 0.343689 seconds and 4 git commands to generate.