Commit | Line | Data |
---|---|---|
7ba29e2a NC |
1 | /* Disassemble Xilinx microblaze instructions. |
2 | ||
250d07de | 3 | Copyright (C) 2009-2021 Free Software Foundation, Inc. |
7ba29e2a NC |
4 | |
5 | This file is part of the GNU opcodes library. | |
6 | ||
7 | This library is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 3, or (at your option) | |
10 | any later version. | |
11 | ||
12 | It is distributed in the hope that it will be useful, but WITHOUT | |
13 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
14 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
15 | License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with this file; see the file COPYING. If not, write to the | |
19 | Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, | |
20 | MA 02110-1301, USA. */ | |
21 | ||
22 | ||
23 | #include "sysdep.h" | |
24 | #define STATIC_TABLE | |
25 | #define DEFINE_TABLE | |
26 | ||
88c1242d | 27 | #include "disassemble.h" |
7ba29e2a | 28 | #include <strings.h> |
ef299415 ME |
29 | #include "microblaze-opc.h" |
30 | #include "microblaze-dis.h" | |
7ba29e2a | 31 | |
378fd436 AM |
32 | #define get_field_rd(buf, instr) get_field (buf, instr, RD_MASK, RD_LOW) |
33 | #define get_field_r1(buf, instr) get_field (buf, instr, RA_MASK, RA_LOW) | |
34 | #define get_field_r2(buf, instr) get_field (buf, instr, RB_MASK, RB_LOW) | |
7ba29e2a NC |
35 | #define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW) |
36 | #define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW) | |
37 | ||
378fd436 AM |
38 | #define NUM_STRBUFS 3 |
39 | #define STRBUF_SIZE 25 | |
fe2d172c | 40 | |
378fd436 AM |
41 | struct string_buf |
42 | { | |
43 | unsigned int which; | |
44 | char str[NUM_STRBUFS][STRBUF_SIZE]; | |
45 | }; | |
46 | ||
47 | static inline char * | |
48 | strbuf (struct string_buf *buf) | |
49 | { | |
50 | #ifdef ENABLE_CHECKING | |
51 | if (buf->which >= NUM_STRBUFS) | |
52 | abort (); | |
53 | #endif | |
54 | return buf->str[buf->which++]; | |
55 | } | |
fe2d172c | 56 | |
7ba29e2a | 57 | static char * |
378fd436 | 58 | get_field (struct string_buf *buf, long instr, long mask, unsigned short low) |
7ba29e2a | 59 | { |
378fd436 | 60 | char *p = strbuf (buf); |
7ba29e2a | 61 | |
378fd436 AM |
62 | sprintf (p, "%s%d", register_prefix, (int)((instr & mask) >> low)); |
63 | return p; | |
7ba29e2a NC |
64 | } |
65 | ||
66 | static char * | |
378fd436 | 67 | get_field_imm (struct string_buf *buf, long instr) |
7ba29e2a | 68 | { |
378fd436 | 69 | char *p = strbuf (buf); |
7ba29e2a | 70 | |
378fd436 AM |
71 | sprintf (p, "%d", (short)((instr & IMM_MASK) >> IMM_LOW)); |
72 | return p; | |
7ba29e2a NC |
73 | } |
74 | ||
75 | static char * | |
378fd436 | 76 | get_field_imm5 (struct string_buf *buf, long instr) |
7ba29e2a | 77 | { |
378fd436 | 78 | char *p = strbuf (buf); |
7ba29e2a | 79 | |
378fd436 AM |
80 | sprintf (p, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW)); |
81 | return p; | |
7ba29e2a NC |
82 | } |
83 | ||
d3da7741 | 84 | static char * |
378fd436 | 85 | get_field_imm5_mbar (struct string_buf *buf, long instr) |
d3da7741 | 86 | { |
378fd436 | 87 | char *p = strbuf (buf); |
d3da7741 | 88 | |
378fd436 AM |
89 | sprintf (p, "%d", (short)((instr & IMM5_MBAR_MASK) >> IMM_MBAR)); |
90 | return p; | |
d3da7741 ME |
91 | } |
92 | ||
7ba29e2a | 93 | static char * |
378fd436 | 94 | get_field_rfsl (struct string_buf *buf, long instr) |
7ba29e2a | 95 | { |
378fd436 | 96 | char *p = strbuf (buf); |
7ba29e2a | 97 | |
378fd436 | 98 | sprintf (p, "%s%d", fsl_register_prefix, |
7ba29e2a | 99 | (short)((instr & RFSL_MASK) >> IMM_LOW)); |
378fd436 | 100 | return p; |
7ba29e2a NC |
101 | } |
102 | ||
103 | static char * | |
378fd436 | 104 | get_field_imm15 (struct string_buf *buf, long instr) |
7ba29e2a | 105 | { |
378fd436 | 106 | char *p = strbuf (buf); |
7ba29e2a | 107 | |
378fd436 AM |
108 | sprintf (p, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW)); |
109 | return p; | |
7ba29e2a NC |
110 | } |
111 | ||
112 | static char * | |
378fd436 AM |
113 | get_field_special (struct string_buf *buf, long instr, |
114 | struct op_code_struct *op) | |
7ba29e2a | 115 | { |
378fd436 AM |
116 | char *p = strbuf (buf); |
117 | char *spr; | |
7ba29e2a NC |
118 | |
119 | switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask)) | |
120 | { | |
121 | case REG_MSR_MASK : | |
378fd436 | 122 | spr = "msr"; |
7ba29e2a NC |
123 | break; |
124 | case REG_PC_MASK : | |
378fd436 | 125 | spr = "pc"; |
7ba29e2a NC |
126 | break; |
127 | case REG_EAR_MASK : | |
378fd436 | 128 | spr = "ear"; |
7ba29e2a NC |
129 | break; |
130 | case REG_ESR_MASK : | |
378fd436 | 131 | spr = "esr"; |
7ba29e2a NC |
132 | break; |
133 | case REG_FSR_MASK : | |
378fd436 | 134 | spr = "fsr"; |
7ba29e2a NC |
135 | break; |
136 | case REG_BTR_MASK : | |
378fd436 | 137 | spr = "btr"; |
7ba29e2a NC |
138 | break; |
139 | case REG_EDR_MASK : | |
378fd436 | 140 | spr = "edr"; |
7ba29e2a NC |
141 | break; |
142 | case REG_PID_MASK : | |
378fd436 | 143 | spr = "pid"; |
7ba29e2a NC |
144 | break; |
145 | case REG_ZPR_MASK : | |
378fd436 | 146 | spr = "zpr"; |
7ba29e2a NC |
147 | break; |
148 | case REG_TLBX_MASK : | |
378fd436 | 149 | spr = "tlbx"; |
7ba29e2a NC |
150 | break; |
151 | case REG_TLBLO_MASK : | |
378fd436 | 152 | spr = "tlblo"; |
7ba29e2a NC |
153 | break; |
154 | case REG_TLBHI_MASK : | |
378fd436 | 155 | spr = "tlbhi"; |
7ba29e2a NC |
156 | break; |
157 | case REG_TLBSX_MASK : | |
378fd436 | 158 | spr = "tlbsx"; |
7ba29e2a | 159 | break; |
0db4b326 | 160 | case REG_SHR_MASK : |
378fd436 | 161 | spr = "shr"; |
0db4b326 ME |
162 | break; |
163 | case REG_SLR_MASK : | |
378fd436 | 164 | spr = "slr"; |
0db4b326 | 165 | break; |
7ba29e2a NC |
166 | default : |
167 | if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000) | |
378fd436 AM |
168 | == REG_PVR_MASK) |
169 | { | |
170 | sprintf (p, "%spvr%d", register_prefix, | |
7ba29e2a | 171 | (unsigned short)(((instr & IMM_MASK) >> IMM_LOW) |
378fd436 AM |
172 | ^ op->immval_mask) ^ REG_PVR_MASK); |
173 | return p; | |
174 | } | |
7ba29e2a | 175 | else |
378fd436 | 176 | spr = "pc"; |
7ba29e2a NC |
177 | break; |
178 | } | |
179 | ||
378fd436 AM |
180 | sprintf (p, "%s%s", register_prefix, spr); |
181 | return p; | |
7ba29e2a NC |
182 | } |
183 | ||
184 | static unsigned long | |
185 | read_insn_microblaze (bfd_vma memaddr, | |
186 | struct disassemble_info *info, | |
187 | struct op_code_struct **opr) | |
188 | { | |
189 | unsigned char ibytes[4]; | |
190 | int status; | |
191 | struct op_code_struct * op; | |
192 | unsigned long inst; | |
193 | ||
194 | status = info->read_memory_func (memaddr, ibytes, 4, info); | |
195 | ||
196 | if (status != 0) | |
197 | { | |
198 | info->memory_error_func (status, memaddr, info); | |
199 | return 0; | |
200 | } | |
201 | ||
202 | if (info->endian == BFD_ENDIAN_BIG) | |
488d02fe AM |
203 | inst = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) |
204 | | (ibytes[2] << 8) | ibytes[3]); | |
7ba29e2a | 205 | else if (info->endian == BFD_ENDIAN_LITTLE) |
488d02fe AM |
206 | inst = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) |
207 | | (ibytes[1] << 8) | ibytes[0]); | |
7ba29e2a NC |
208 | else |
209 | abort (); | |
210 | ||
211 | /* Just a linear search of the table. */ | |
212 | for (op = opcodes; op->name != 0; op ++) | |
213 | if (op->bit_sequence == (inst & op->opcode_mask)) | |
214 | break; | |
215 | ||
216 | *opr = op; | |
217 | return inst; | |
218 | } | |
219 | ||
220 | ||
221 | int | |
222 | print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info) | |
223 | { | |
91d6fa6a | 224 | fprintf_ftype print_func = info->fprintf_func; |
7ba29e2a NC |
225 | void * stream = info->stream; |
226 | unsigned long inst, prev_inst; | |
227 | struct op_code_struct * op, *pop; | |
228 | int immval = 0; | |
229 | bfd_boolean immfound = FALSE; | |
230 | static bfd_vma prev_insn_addr = -1; /* Init the prev insn addr. */ | |
231 | static int prev_insn_vma = -1; /* Init the prev insn vma. */ | |
232 | int curr_insn_vma = info->buffer_vma; | |
378fd436 | 233 | struct string_buf buf; |
7ba29e2a | 234 | |
378fd436 | 235 | buf.which = 0; |
7ba29e2a NC |
236 | info->bytes_per_chunk = 4; |
237 | ||
238 | inst = read_insn_microblaze (memaddr, info, &op); | |
239 | if (inst == 0) | |
240 | return -1; | |
241 | ||
242 | if (prev_insn_vma == curr_insn_vma) | |
243 | { | |
244 | if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) | |
378fd436 AM |
245 | { |
246 | prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop); | |
7ba29e2a NC |
247 | if (prev_inst == 0) |
248 | return -1; | |
249 | if (pop->instr == imm) | |
250 | { | |
251 | immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000; | |
252 | immfound = TRUE; | |
253 | } | |
254 | else | |
255 | { | |
256 | immval = 0; | |
257 | immfound = FALSE; | |
258 | } | |
259 | } | |
260 | } | |
261 | ||
262 | /* Make curr insn as prev insn. */ | |
263 | prev_insn_addr = memaddr; | |
264 | prev_insn_vma = curr_insn_vma; | |
265 | ||
266 | if (op->name == NULL) | |
d908c8af | 267 | print_func (stream, ".short 0x%04x", (unsigned int) inst); |
7ba29e2a NC |
268 | else |
269 | { | |
91d6fa6a | 270 | print_func (stream, "%s", op->name); |
7ba29e2a NC |
271 | |
272 | switch (op->inst_type) | |
273 | { | |
378fd436 AM |
274 | case INST_TYPE_RD_R1_R2: |
275 | print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst), | |
276 | get_field_r1 (&buf, inst), get_field_r2 (&buf, inst)); | |
277 | break; | |
278 | case INST_TYPE_RD_R1_IMM: | |
279 | print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst), | |
280 | get_field_r1 (&buf, inst), get_field_imm (&buf, inst)); | |
7ba29e2a NC |
281 | if (info->print_address_func && get_int_field_r1 (inst) == 0 |
282 | && info->symbol_at_address_func) | |
283 | { | |
284 | if (immfound) | |
378fd436 | 285 | immval |= (get_int_field_imm (inst) & 0x0000ffff); |
7ba29e2a NC |
286 | else |
287 | { | |
378fd436 AM |
288 | immval = get_int_field_imm (inst); |
289 | if (immval & 0x8000) | |
7ba29e2a | 290 | immval |= 0xFFFF0000; |
378fd436 | 291 | } |
7ba29e2a NC |
292 | if (immval > 0 && info->symbol_at_address_func (immval, info)) |
293 | { | |
378fd436 AM |
294 | print_func (stream, "\t// "); |
295 | info->print_address_func (immval, info); | |
296 | } | |
7ba29e2a NC |
297 | } |
298 | break; | |
299 | case INST_TYPE_RD_R1_IMM5: | |
378fd436 AM |
300 | print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst), |
301 | get_field_r1 (&buf, inst), get_field_imm5 (&buf, inst)); | |
7ba29e2a NC |
302 | break; |
303 | case INST_TYPE_RD_RFSL: | |
378fd436 AM |
304 | print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), |
305 | get_field_rfsl (&buf, inst)); | |
7ba29e2a NC |
306 | break; |
307 | case INST_TYPE_R1_RFSL: | |
378fd436 AM |
308 | print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), |
309 | get_field_rfsl (&buf, inst)); | |
7ba29e2a NC |
310 | break; |
311 | case INST_TYPE_RD_SPECIAL: | |
378fd436 AM |
312 | print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), |
313 | get_field_special (&buf, inst, op)); | |
7ba29e2a NC |
314 | break; |
315 | case INST_TYPE_SPECIAL_R1: | |
378fd436 AM |
316 | print_func (stream, "\t%s, %s", get_field_special (&buf, inst, op), |
317 | get_field_r1 (&buf, inst)); | |
7ba29e2a NC |
318 | break; |
319 | case INST_TYPE_RD_R1: | |
378fd436 AM |
320 | print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), |
321 | get_field_r1 (&buf, inst)); | |
7ba29e2a NC |
322 | break; |
323 | case INST_TYPE_R1_R2: | |
378fd436 AM |
324 | print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), |
325 | get_field_r2 (&buf, inst)); | |
7ba29e2a NC |
326 | break; |
327 | case INST_TYPE_R1_IMM: | |
378fd436 AM |
328 | print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), |
329 | get_field_imm (&buf, inst)); | |
7ba29e2a NC |
330 | /* The non-pc relative instructions are returns, which shouldn't |
331 | have a label printed. */ | |
332 | if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET | |
333 | && info->symbol_at_address_func) | |
334 | { | |
335 | if (immfound) | |
378fd436 | 336 | immval |= (get_int_field_imm (inst) & 0x0000ffff); |
7ba29e2a NC |
337 | else |
338 | { | |
378fd436 AM |
339 | immval = get_int_field_imm (inst); |
340 | if (immval & 0x8000) | |
7ba29e2a | 341 | immval |= 0xFFFF0000; |
378fd436 | 342 | } |
7ba29e2a NC |
343 | immval += memaddr; |
344 | if (immval > 0 && info->symbol_at_address_func (immval, info)) | |
345 | { | |
378fd436 AM |
346 | print_func (stream, "\t// "); |
347 | info->print_address_func (immval, info); | |
348 | } | |
7ba29e2a NC |
349 | else |
350 | { | |
378fd436 AM |
351 | print_func (stream, "\t\t// "); |
352 | print_func (stream, "%x", immval); | |
353 | } | |
7ba29e2a NC |
354 | } |
355 | break; | |
378fd436 AM |
356 | case INST_TYPE_RD_IMM: |
357 | print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), | |
358 | get_field_imm (&buf, inst)); | |
7ba29e2a NC |
359 | if (info->print_address_func && info->symbol_at_address_func) |
360 | { | |
378fd436 AM |
361 | if (immfound) |
362 | immval |= (get_int_field_imm (inst) & 0x0000ffff); | |
363 | else | |
364 | { | |
365 | immval = get_int_field_imm (inst); | |
366 | if (immval & 0x8000) | |
367 | immval |= 0xFFFF0000; | |
368 | } | |
369 | if (op->inst_offset_type == INST_PC_OFFSET) | |
370 | immval += (int) memaddr; | |
371 | if (info->symbol_at_address_func (immval, info)) | |
372 | { | |
373 | print_func (stream, "\t// "); | |
374 | info->print_address_func (immval, info); | |
375 | } | |
7ba29e2a NC |
376 | } |
377 | break; | |
378fd436 AM |
378 | case INST_TYPE_IMM: |
379 | print_func (stream, "\t%s", get_field_imm (&buf, inst)); | |
7ba29e2a NC |
380 | if (info->print_address_func && info->symbol_at_address_func |
381 | && op->instr != imm) | |
382 | { | |
383 | if (immfound) | |
378fd436 | 384 | immval |= (get_int_field_imm (inst) & 0x0000ffff); |
7ba29e2a NC |
385 | else |
386 | { | |
378fd436 AM |
387 | immval = get_int_field_imm (inst); |
388 | if (immval & 0x8000) | |
7ba29e2a | 389 | immval |= 0xFFFF0000; |
378fd436 | 390 | } |
7ba29e2a | 391 | if (op->inst_offset_type == INST_PC_OFFSET) |
378fd436 | 392 | immval += (int) memaddr; |
7ba29e2a NC |
393 | if (immval > 0 && info->symbol_at_address_func (immval, info)) |
394 | { | |
378fd436 AM |
395 | print_func (stream, "\t// "); |
396 | info->print_address_func (immval, info); | |
397 | } | |
7ba29e2a NC |
398 | else if (op->inst_offset_type == INST_PC_OFFSET) |
399 | { | |
378fd436 AM |
400 | print_func (stream, "\t\t// "); |
401 | print_func (stream, "%x", immval); | |
402 | } | |
7ba29e2a NC |
403 | } |
404 | break; | |
378fd436 AM |
405 | case INST_TYPE_RD_R2: |
406 | print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), | |
407 | get_field_r2 (&buf, inst)); | |
7ba29e2a NC |
408 | break; |
409 | case INST_TYPE_R2: | |
378fd436 | 410 | print_func (stream, "\t%s", get_field_r2 (&buf, inst)); |
7ba29e2a NC |
411 | break; |
412 | case INST_TYPE_R1: | |
378fd436 | 413 | print_func (stream, "\t%s", get_field_r1 (&buf, inst)); |
7ba29e2a | 414 | break; |
94dda8b7 | 415 | case INST_TYPE_R1_R2_SPECIAL: |
378fd436 AM |
416 | print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), |
417 | get_field_r2 (&buf, inst)); | |
7ba29e2a NC |
418 | break; |
419 | case INST_TYPE_RD_IMM15: | |
378fd436 AM |
420 | print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), |
421 | get_field_imm15 (&buf, inst)); | |
422 | break; | |
423 | /* For mbar insn. */ | |
424 | case INST_TYPE_IMM5: | |
425 | print_func (stream, "\t%s", get_field_imm5_mbar (&buf, inst)); | |
426 | break; | |
427 | /* For mbar 16 or sleep insn. */ | |
428 | case INST_TYPE_NONE: | |
7ba29e2a | 429 | break; |
378fd436 | 430 | /* For tuqula instruction */ |
7ba29e2a | 431 | case INST_TYPE_RD: |
378fd436 | 432 | print_func (stream, "\t%s", get_field_rd (&buf, inst)); |
7ba29e2a NC |
433 | break; |
434 | case INST_TYPE_RFSL: | |
378fd436 | 435 | print_func (stream, "\t%s", get_field_rfsl (&buf, inst)); |
7ba29e2a NC |
436 | break; |
437 | default: | |
438 | /* If the disassembler lags the instruction set. */ | |
378fd436 AM |
439 | print_func (stream, "\tundecoded operands, inst is 0x%04x", |
440 | (unsigned int) inst); | |
7ba29e2a NC |
441 | break; |
442 | } | |
443 | } | |
444 | ||
445 | /* Say how many bytes we consumed. */ | |
446 | return 4; | |
447 | } | |
fe2d172c ME |
448 | |
449 | enum microblaze_instr | |
7ba29e2a NC |
450 | get_insn_microblaze (long inst, |
451 | bfd_boolean *isunsignedimm, | |
452 | enum microblaze_instr_type *insn_type, | |
453 | short *delay_slots) | |
454 | { | |
455 | struct op_code_struct * op; | |
456 | *isunsignedimm = FALSE; | |
457 | ||
458 | /* Just a linear search of the table. */ | |
459 | for (op = opcodes; op->name != 0; op ++) | |
460 | if (op->bit_sequence == (inst & op->opcode_mask)) | |
461 | break; | |
462 | ||
463 | if (op->name == 0) | |
464 | return invalid_inst; | |
465 | else | |
466 | { | |
467 | *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM); | |
468 | *insn_type = op->instr_type; | |
469 | *delay_slots = op->delay_slots; | |
470 | return op->instr; | |
471 | } | |
472 | } | |
473 | ||
7ba29e2a | 474 | enum microblaze_instr |
91d6fa6a | 475 | microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed) |
7ba29e2a NC |
476 | { |
477 | enum microblaze_instr op; | |
478 | bfd_boolean t1; | |
479 | enum microblaze_instr_type t2; | |
480 | short t3; | |
481 | ||
482 | op = get_insn_microblaze (insn, &t1, &t2, &t3); | |
483 | *rd = (insn & RD_MASK) >> RD_LOW; | |
484 | *ra = (insn & RA_MASK) >> RA_LOW; | |
485 | *rb = (insn & RB_MASK) >> RB_LOW; | |
486 | t3 = (insn & IMM_MASK) >> IMM_LOW; | |
91d6fa6a | 487 | *immed = (int) t3; |
7ba29e2a NC |
488 | return (op); |
489 | } | |
490 | ||
491 | unsigned long | |
492 | microblaze_get_target_address (long inst, bfd_boolean immfound, int immval, | |
493 | long pcval, long r1val, long r2val, | |
494 | bfd_boolean *targetvalid, | |
495 | bfd_boolean *unconditionalbranch) | |
496 | { | |
497 | struct op_code_struct * op; | |
498 | long targetaddr = 0; | |
499 | ||
500 | *unconditionalbranch = FALSE; | |
501 | /* Just a linear search of the table. */ | |
502 | for (op = opcodes; op->name != 0; op ++) | |
503 | if (op->bit_sequence == (inst & op->opcode_mask)) | |
504 | break; | |
505 | ||
506 | if (op->name == 0) | |
507 | { | |
508 | *targetvalid = FALSE; | |
509 | } | |
510 | else if (op->instr_type == branch_inst) | |
511 | { | |
512 | switch (op->inst_type) | |
513 | { | |
514 | case INST_TYPE_R2: | |
515 | *unconditionalbranch = TRUE; | |
516 | /* Fall through. */ | |
517 | case INST_TYPE_RD_R2: | |
518 | case INST_TYPE_R1_R2: | |
519 | targetaddr = r2val; | |
520 | *targetvalid = TRUE; | |
521 | if (op->inst_offset_type == INST_PC_OFFSET) | |
522 | targetaddr += pcval; | |
523 | break; | |
524 | case INST_TYPE_IMM: | |
525 | *unconditionalbranch = TRUE; | |
526 | /* Fall through. */ | |
527 | case INST_TYPE_RD_IMM: | |
528 | case INST_TYPE_R1_IMM: | |
529 | if (immfound) | |
530 | { | |
531 | targetaddr = (immval << 16) & 0xffff0000; | |
532 | targetaddr |= (get_int_field_imm (inst) & 0x0000ffff); | |
533 | } | |
534 | else | |
535 | { | |
536 | targetaddr = get_int_field_imm (inst); | |
537 | if (targetaddr & 0x8000) | |
538 | targetaddr |= 0xFFFF0000; | |
539 | } | |
540 | if (op->inst_offset_type == INST_PC_OFFSET) | |
541 | targetaddr += pcval; | |
542 | *targetvalid = TRUE; | |
543 | break; | |
544 | default: | |
545 | *targetvalid = FALSE; | |
546 | break; | |
547 | } | |
548 | } | |
549 | else if (op->instr_type == return_inst) | |
550 | { | |
551 | if (immfound) | |
552 | { | |
553 | targetaddr = (immval << 16) & 0xffff0000; | |
554 | targetaddr |= (get_int_field_imm (inst) & 0x0000ffff); | |
555 | } | |
556 | else | |
557 | { | |
558 | targetaddr = get_int_field_imm (inst); | |
559 | if (targetaddr & 0x8000) | |
560 | targetaddr |= 0xFFFF0000; | |
561 | } | |
562 | targetaddr += r1val; | |
563 | *targetvalid = TRUE; | |
564 | } | |
565 | else | |
566 | *targetvalid = FALSE; | |
567 | return targetaddr; | |
568 | } |