This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / opcodes / v850-dis.c
1 /* Disassemble V850 instructions.
2 Copyright (C) 1996 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
25 static 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",
29 "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
30
31 static const char *const v850_sreg_names[] =
32 { "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7",
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 */
38 "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
39 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
40
41 static const char *const v850_cc_names[] =
42 { "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
43 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
44
45 static int
46 disassemble (memaddr, info, insn)
47 bfd_vma memaddr;
48 struct disassemble_info *info;
49 unsigned long insn;
50 {
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;
56 int target_processor;
57
58 /* start-sanitize-v850e */
59 /* Special case: 32 bit MOV */
60 if ((insn & 0xffe0) == 0x0620)
61 short_op = true;
62 /* end-sanitize-v850e */
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 /* 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
88 /* Find the opcode. */
89 while (op->name)
90 {
91 if ((op->mask & insn) == op->opcode
92 && (op->processors & target_processor))
93 {
94 const unsigned char * opindex_ptr;
95 unsigned int opnum;
96 unsigned int memop;
97
98 match = 1;
99 (*info->fprintf_func) (info->stream, "%s\t", op->name);
100 //fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );
101
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.
110
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
125 operand = &v850_operands[*opindex_ptr];
126
127 if (operand->extract)
128 value = (operand->extract) (insn, 0);
129 else
130 {
131 if (operand->bits == -1)
132 value = (insn & operand->shift);
133 else
134 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
135
136 if (operand->flags & V850_OPERAND_SIGNED)
137 value = ((long)(value << (32 - operand->bits))
138 >> (32 - operand->bits));
139 }
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;
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;
182 default: info->fprintf_func (info->stream, "%d", value); break;
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
207 /* start-sanitize-v850e */
208 case V850E_PUSH_POP:
209 {
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 };
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 };
213 int * regs;
214 int i;
215 unsigned long int mask = 0;
216 int pc = false;
217 int sr = false;
218
219
220 switch (operand->shift)
221 {
222 case 0xffe00001: regs = list12_regs; break;
223 case 0xfff8000f: regs = list18_h_regs; break;
224 case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break; /* Do not include magic bit */
225 default:
226 fprintf (stderr, "unknown operand shift: %x\n", operand->shift );
227 abort();
228 }
229
230 for (i = 0; i < 32; i++)
231 {
232 if (value & (1 << i))
233 {
234 switch (regs[ i ])
235 {
236 default: mask |= (1 << regs[ i ]); break;
237 case 0: fprintf (stderr, "unknown pop reg: %d\n", i ); abort();
238 case -1: pc = true; break;
239 case -2: sr = true; break;
240 }
241 }
242 }
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
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, "]");
328 }
329
330 /* Close any square bracket we left open. */
331 if (memop && opnum == memop + 2)
332 (*info->fprintf_func) (info->stream, "]");
333
334 /* All done. */
335 break;
336 }
337 op++;
338 }
339
340 if (!match)
341 {
342 if (short_op)
343 info->fprintf_func (info->stream, ".short\t0x%04x", insn);
344 else
345 info->fprintf_func (info->stream, ".long\t0x%08x", insn);
346 }
347
348 return bytes_read;
349 }
350
351 int
352 print_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.038951 seconds and 5 git commands to generate.