Made immediate parameter of MOVHI be unsigned
[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", "r31" };
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 "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
35 "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
36
37 static const char *const v850_cc_names[] =
38 { "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
39 "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
40
41 static int
42 disassemble (memaddr, info, insn)
43 bfd_vma memaddr;
44 struct disassemble_info *info;
45 unsigned long insn;
46 {
47 struct v850_opcode * op = (struct v850_opcode *)v850_opcodes;
48 const struct v850_operand * operand;
49 int match = 0;
50 int short_op = ((insn & 0x0600) != 0x0600);
51 int bytes_read;
52
53
54 /* Special case: 32 bit MOV */
55 if ((insn & 0xffe0) == 0x0620)
56 short_op = true;
57
58 bytes_read = short_op ? 2 : 4;
59
60 /* If this is a two byte insn, then mask off the high bits. */
61 if (short_op)
62 insn &= 0xffff;
63
64 /* Find the opcode. */
65 while (op->name)
66 {
67 if ((op->mask & insn) == op->opcode)
68 {
69 const unsigned char * opindex_ptr;
70 unsigned int opnum;
71 unsigned int memop;
72
73 match = 1;
74 (*info->fprintf_func) (info->stream, "%s\t", op->name);
75 //fprintf (stderr, "match: mask: %x insn: %x, opcode: %x, name: %s\n", op->mask, insn, op->opcode, op->name );
76
77 memop = op->memop;
78 /* Now print the operands.
79
80 MEMOP is the operand number at which a memory
81 address specification starts, or zero if this
82 instruction has no memory addresses.
83
84 A memory address is always two arguments.
85
86 This information allows us to determine when to
87 insert commas into the output stream as well as
88 when to insert disp[reg] expressions onto the
89 output stream. */
90
91 for (opindex_ptr = op->operands, opnum = 1;
92 *opindex_ptr != 0;
93 opindex_ptr++, opnum++)
94 {
95 long value;
96 int flag;
97 int status;
98 bfd_byte buffer[ 4 ];
99
100 operand = &v850_operands[*opindex_ptr];
101
102 if (operand->extract)
103 value = (operand->extract) (insn, 0);
104 else if (operand->bits == -1)
105 value = (insn & operand->shift);
106 else
107 value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
108
109 if (operand->flags & V850_OPERAND_SIGNED)
110 value = ((long)(value << (32 - operand->bits))
111 >> (32 - operand->bits));
112
113 /* The first operand is always output without any
114 special handling.
115
116 For the following arguments:
117
118 If memop && opnum == memop + 1, then we need '[' since
119 we're about to output the register used in a memory
120 reference.
121
122 If memop && opnum == memop + 2, then we need ']' since
123 we just finished the register in a memory reference. We
124 also need a ',' before this operand.
125
126 Else we just need a comma.
127
128 We may need to output a trailing ']' if the last operand
129 in an instruction is the register for a memory address.
130
131 The exception (and there's always an exception) is the
132 "jmp" insn which needs square brackets around it's only
133 register argument. */
134
135 if (memop && opnum == memop + 1) info->fprintf_func (info->stream, "[");
136 else if (memop && opnum == memop + 2) info->fprintf_func (info->stream, "],");
137 else if (memop == 1 && opnum == 1
138 && (operand->flags & V850_OPERAND_REG))
139 info->fprintf_func (info->stream, "[");
140 else if (opnum > 1) info->fprintf_func (info->stream, ", ");
141
142 /* extract the flags, ignorng ones which do not effect disassembly output. */
143 flag = operand->flags;
144 flag &= ~ V850_OPERAND_SIGNED;
145 flag &= ~ V850_OPERAND_RELAX;
146 flag &= ~ V850_OPERAND_ADJUST_SHORT_MEMORY;
147 flag &= - flag;
148
149 switch (flag)
150 {
151 case V850_OPERAND_REG: info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
152 case V850_OPERAND_SRG: info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
153 case V850_OPERAND_CC: info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
154 case V850_OPERAND_EP: info->fprintf_func (info->stream, "ep"); break;
155 case V850_OPERAND_DISP: info->print_address_func (value + memaddr, info); break;
156 default: info->fprintf_func (info->stream, "%d", value); break;
157 /* start-sanitize-v850e */
158 case V850E_PUSH_POP:
159 {
160 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 };
161 /* start-sanitize-v850eq */
162 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 };
163 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 };
164 /* end-sanitize-v850eq */
165 int * regs;
166 int i;
167 int shown_one = false;
168
169 switch (operand->shift)
170 {
171 case 0xffe00001: regs = list12_regs; break;
172 /* start-sanitize-v850eq */
173 case 0xfff8000f: regs = list18_h_regs; break;
174 case 0xfff8001f: regs = list18_l_regs; value &= ~0x10; break; /* Do not include magic bit */
175 /* end-sanitize-v850eq */
176 default:
177 fprintf (stderr, "unknown operand shift: %x\n", operand->shift );
178 abort();
179 }
180
181 info->fprintf_func (info->stream, "{");
182 for (i = 0; i < 32; i++)
183 {
184 if (value & (1 << i))
185 {
186 if (shown_one)
187 info->fprintf_func (info->stream, ",");
188 else
189 shown_one = true;
190
191 switch (regs[ i ])
192 {
193 default: info->fprintf_func (info->stream, "%s", v850_reg_names[regs[ i ]]); break;
194 /* start-sanitize-v850eq */
195 case 0: fprintf (stderr, "unknown pop reg: %d\n", i ); abort();
196 case -1: info->fprintf_func (info->stream, "PC "); break;
197 case -2: info->fprintf_func (info->stream, "SR"); break;
198 /* end-sanitize-v850eq */
199 }
200 }
201 }
202 info->fprintf_func (info->stream, "}");
203 }
204 break;
205
206 case V850E_IMMEDIATE16:
207 status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
208 if (status == 0)
209 {
210 bytes_read += 2;
211 value = bfd_getl16 (buffer);
212
213 /* If this is a DISPOSE instruction with ff set to 0x10, then shift value up by 16. */
214 if ((insn & 0x001fffc0) == 0x00130780)
215 value <<= 16;
216
217 info->fprintf_func (info->stream, "0x%x", value);
218 }
219 else
220 {
221 info->memory_error_func (status, memaddr + bytes_read, info);
222 }
223 break;
224
225 case V850E_IMMEDIATE32:
226 status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
227 if (status == 0)
228 {
229 bytes_read += 4;
230 value = bfd_getl32 (buffer);
231 info->fprintf_func (info->stream, "0x%lx", value);
232 }
233 else
234 {
235 info->memory_error_func (status, memaddr + bytes_read, info);
236 }
237 break;
238 /* end-sanitize-v850e */
239 }
240
241 /* Handle jmp correctly. */
242 if (memop == 1 && opnum == 1
243 && ((operand->flags & V850_OPERAND_REG) != 0))
244 (*info->fprintf_func) (info->stream, "]");
245 }
246
247 /* Close any square bracket we left open. */
248 if (memop && opnum == memop + 2)
249 (*info->fprintf_func) (info->stream, "]");
250
251 /* All done. */
252 break;
253 }
254 op++;
255 }
256
257 if (!match)
258 {
259 if (short_op)
260 info->fprintf_func (info->stream, ".short\t0x%04x", insn);
261 else
262 info->fprintf_func (info->stream, ".long\t0x%08x", insn);
263 }
264
265 return bytes_read;
266 }
267
268 int
269 print_insn_v850 (memaddr, info)
270 bfd_vma memaddr;
271 struct disassemble_info * info;
272 {
273 int status;
274 bfd_byte buffer[ 4 ];
275 unsigned long insn;
276
277 /* First figure out how big the opcode is. */
278
279 status = info->read_memory_func (memaddr, buffer, 2, info);
280 if (status == 0)
281 {
282 insn = bfd_getl16 (buffer);
283
284 if ( (insn & 0x0600) == 0x0600
285 && (insn & 0xffe0) != 0x0620)
286 {
287 /* If this is a 4 byte insn, read 4 bytes of stuff. */
288 status = info->read_memory_func (memaddr, buffer, 4, info);
289
290 if (status == 0)
291 insn = bfd_getl32 (buffer);
292 }
293 }
294
295 if (status != 0)
296 {
297 info->memory_error_func (status, memaddr, info);
298 return -1;
299 }
300
301 /* Make sure we tell our caller how many bytes we consumed. */
302 return disassemble (memaddr, info, insn);
303 }
304
305
This page took 0.037834 seconds and 4 git commands to generate.