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