Commit | Line | Data |
---|---|---|
1fe1f39c NC |
1 | /* Disassembler code for CRX. |
2 | Copyright 2004 Free Software Foundation, Inc. | |
3 | Contributed by Tomer Levi, NSC, Israel. | |
4 | Written by Tomer Levi. | |
5 | ||
6 | This file is part of the GNU binutils and GDB, the GNU debugger. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify it under | |
9 | the terms of the GNU General Public License as published by the Free | |
10 | Software Foundation; either version 2, or (at your option) | |
11 | any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, but WITHOUT | |
14 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
16 | more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program; if not, write to the Free Software | |
20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
21 | ||
22 | #include "dis-asm.h" | |
23 | #include "sysdep.h" | |
24 | #include "opcode/crx.h" | |
25 | ||
26 | /* String to print when opcode was not matched. */ | |
27 | #define ILLEGAL "illegal" | |
28 | /* Escape to 16-bit immediate. */ | |
29 | #define ESCAPE_16_BIT 0xE | |
30 | ||
31 | /* Extract 'n_bits' from 'a' starting from offset 'offs'. */ | |
32 | #define EXTRACT(a, offs, n_bits) \ | |
33 | (n_bits == 32 ? (((a) >> (offs)) & ~0L) \ | |
34 | : (((a) >> (offs)) & ((1 << (n_bits)) -1))) | |
35 | ||
36 | /* Set Bit Mask - a mask to set all bits starting from offset 'offs'. */ | |
37 | #define SBM(offs) ((((1 << (32 - offs)) -1) << (offs))) | |
38 | ||
39 | typedef unsigned long dwordU; | |
40 | typedef unsigned short wordU; | |
41 | ||
42 | typedef struct | |
43 | { | |
44 | dwordU val; | |
45 | int nbits; | |
46 | } parameter; | |
47 | ||
48 | /* Structure to hold valid 'cinv' instruction options. */ | |
49 | ||
50 | typedef struct | |
51 | { | |
52 | /* Cinv printed string. */ | |
53 | char *str; | |
54 | /* Value corresponding to the string. */ | |
55 | unsigned int value; | |
56 | } | |
57 | cinv_entry; | |
58 | ||
59 | /* CRX 'cinv' options. */ | |
60 | const cinv_entry crx_cinvs[] = | |
61 | { | |
48c9f030 NC |
62 | {"[i]", 2}, {"[i,u]", 3}, {"[d]", 4}, {"[d,u]", 5}, |
63 | {"[d,i]", 6}, {"[d,i,u]", 7}, {"[b]", 8}, | |
64 | {"[b,i]", 10}, {"[b,i,u]", 11}, {"[b,d]", 12}, | |
65 | {"[b,d,u]", 13}, {"[b,d,i]", 14}, {"[b,d,i,u]", 15} | |
1fe1f39c NC |
66 | }; |
67 | ||
48c9f030 NC |
68 | /* Enum to distinguish CO-Processor [special] registers arguments |
69 | from general purpose regidters. */ | |
70 | typedef enum COP_ARG_TYPE | |
71 | { | |
72 | /* Not a CO-Processor argument (probably a general purpose reg.). */ | |
73 | NO_COP_ARG = 0, | |
74 | /* A CO-Processor argument (c<N>). */ | |
75 | COP_ARG, | |
76 | /* A CO-Processor special argument (cs<N>). */ | |
77 | COPS_ARG | |
78 | } | |
79 | COP_ARG_TYPE; | |
80 | ||
1fe1f39c NC |
81 | /* Number of valid 'cinv' instruction options. */ |
82 | int NUMCINVS = ((sizeof crx_cinvs)/(sizeof crx_cinvs[0])); | |
83 | /* Current opcode table entry we're disassembling. */ | |
84 | const inst *instruction; | |
85 | /* Current instruction we're disassembling. */ | |
86 | ins currInsn; | |
87 | /* The current instruction is read into 3 consecutive words. */ | |
88 | wordU words[3]; | |
89 | /* Contains all words in appropriate order. */ | |
90 | ULONGLONG allWords; | |
91 | /* Holds the current processed argument number. */ | |
92 | int processing_argument_number; | |
93 | /* Nonzero means a CST4 instruction. */ | |
94 | int cst4flag; | |
95 | /* Nonzero means the instruction's original size is | |
96 | incremented (escape sequence is used). */ | |
97 | int size_changed; | |
98 | ||
99 | static int get_number_of_operands (void); | |
100 | static argtype getargtype (operand_type); | |
101 | static int getbits (operand_type); | |
102 | static char *getregname (reg); | |
103 | static char *getcopregname (copreg, reg_type); | |
104 | static char * getprocregname (int); | |
105 | static char *gettrapstring (unsigned); | |
106 | static char *getcinvstring (unsigned); | |
48c9f030 | 107 | static void getregliststring (int, char *, enum COP_ARG_TYPE); |
1fe1f39c NC |
108 | static wordU get_word_at_PC (bfd_vma, struct disassemble_info *); |
109 | static void get_words_at_PC (bfd_vma, struct disassemble_info *); | |
110 | static unsigned long build_mask (void); | |
111 | static int powerof2 (int); | |
112 | static int match_opcode (void); | |
113 | static void make_instruction (void); | |
114 | static void print_arguments (ins *, struct disassemble_info *); | |
115 | static void print_arg (argument *, struct disassemble_info *); | |
116 | ||
117 | /* Retrieve the number of operands for the current assembled instruction. */ | |
118 | ||
119 | static int | |
120 | get_number_of_operands (void) | |
121 | { | |
122 | int i; | |
123 | ||
124 | for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++) | |
125 | ; | |
126 | ||
127 | return i; | |
128 | } | |
129 | ||
130 | /* Return the bit size for a given operand. */ | |
131 | ||
132 | static int | |
133 | getbits (operand_type op) | |
134 | { | |
135 | if (op < MAX_OPRD) | |
136 | return crx_optab[op].bit_size; | |
137 | else | |
138 | return 0; | |
139 | } | |
140 | ||
141 | /* Return the argument type of a given operand. */ | |
142 | ||
143 | static argtype | |
144 | getargtype (operand_type op) | |
145 | { | |
146 | if (op < MAX_OPRD) | |
147 | return crx_optab[op].arg_type; | |
148 | else | |
149 | return nullargs; | |
150 | } | |
151 | ||
152 | /* Given the trap index in dispatch table, return its name. | |
153 | This routine is used when disassembling the 'excp' instruction. */ | |
154 | ||
155 | static char * | |
156 | gettrapstring (unsigned int index) | |
157 | { | |
158 | const trap_entry *trap; | |
159 | ||
160 | for (trap = crx_traps; trap < crx_traps + NUMTRAPS; trap++) | |
161 | if (trap->entry == index) | |
162 | return trap->name; | |
163 | ||
164 | return ILLEGAL; | |
165 | } | |
166 | ||
167 | /* Given a 'cinv' instruction constant operand, return its corresponding string. | |
168 | This routine is used when disassembling the 'cinv' instruction. */ | |
169 | ||
170 | static char * | |
171 | getcinvstring (unsigned int num) | |
172 | { | |
173 | const cinv_entry *cinv; | |
174 | ||
175 | for (cinv = crx_cinvs; cinv < (crx_cinvs + NUMCINVS); cinv++) | |
176 | if (cinv->value == num) | |
177 | return cinv->str; | |
178 | ||
179 | return ILLEGAL; | |
180 | } | |
181 | ||
182 | /* Given a register enum value, retrieve its name. */ | |
183 | ||
184 | char * | |
185 | getregname (reg r) | |
186 | { | |
187 | const reg_entry *reg = &crx_regtab[r]; | |
188 | ||
189 | if (reg->type != CRX_R_REGTYPE) | |
190 | return ILLEGAL; | |
191 | else | |
192 | return reg->name; | |
193 | } | |
194 | ||
195 | /* Given a coprocessor register enum value, retrieve its name. */ | |
196 | ||
197 | char * | |
198 | getcopregname (copreg r, reg_type type) | |
199 | { | |
200 | const reg_entry *reg; | |
201 | ||
202 | if (type == CRX_C_REGTYPE) | |
203 | reg = &crx_copregtab[r]; | |
204 | else if (type == CRX_CS_REGTYPE) | |
205 | reg = &crx_copregtab[r+(cs0-c0)]; | |
206 | else | |
207 | return ILLEGAL; | |
208 | ||
209 | return reg->name; | |
210 | } | |
211 | ||
212 | ||
213 | /* Getting a processor register name. */ | |
214 | ||
215 | static char * | |
216 | getprocregname (int index) | |
217 | { | |
218 | const reg_entry *r; | |
219 | ||
220 | for (r = crx_regtab; r < crx_regtab + NUMREGS; r++) | |
221 | if (r->image == index) | |
222 | return r->name; | |
223 | ||
224 | return "ILLEGAL REGISTER"; | |
225 | } | |
226 | ||
227 | /* Get the power of two for a given integer. */ | |
228 | ||
229 | static int | |
230 | powerof2 (int x) | |
231 | { | |
232 | int product, i; | |
233 | ||
234 | for (i = 0, product = 1; i < x; i++) | |
235 | product *= 2; | |
236 | ||
237 | return product; | |
238 | } | |
239 | ||
240 | /* Transform a register bit mask to a register list. */ | |
241 | ||
242 | void | |
48c9f030 | 243 | getregliststring (int trap, char *string, enum COP_ARG_TYPE core_cop) |
1fe1f39c NC |
244 | { |
245 | char temp_string[5]; | |
246 | int i; | |
247 | ||
248 | string[0] = '{'; | |
249 | string[1] = '\0'; | |
250 | ||
251 | for (i = 0; i < 16; i++) | |
252 | { | |
253 | if (trap & 0x1) | |
48c9f030 NC |
254 | { |
255 | switch (core_cop) | |
256 | { | |
257 | case NO_COP_ARG: | |
258 | sprintf (temp_string, "r%d", i); | |
259 | break; | |
260 | case COP_ARG: | |
261 | sprintf (temp_string, "c%d", i); | |
262 | break; | |
263 | case COPS_ARG: | |
264 | sprintf (temp_string, "cs%d", i); | |
265 | break; | |
266 | default: | |
267 | break; | |
268 | } | |
1fe1f39c NC |
269 | strcat (string, temp_string); |
270 | if (trap & 0xfffe) | |
271 | strcat (string, ","); | |
272 | } | |
273 | trap = trap >> 1; | |
274 | } | |
275 | ||
276 | strcat (string, "}"); | |
277 | } | |
278 | ||
279 | /* START and END are relating 'allWords' struct, which is 48 bits size. | |
280 | ||
281 | START|--------|END | |
282 | +---------+---------+---------+---------+ | |
283 | | | V | A | L | | |
284 | +---------+---------+---------+---------+ | |
285 | 0 16 32 48 | |
286 | words [0] [1] [2] */ | |
287 | ||
288 | static parameter | |
289 | makelongparameter (ULONGLONG val, int start, int end) | |
290 | { | |
291 | parameter p; | |
292 | ||
293 | p.val = (dwordU) EXTRACT(val, 48 - end, end - start); | |
294 | p.nbits = end - start; | |
295 | return p; | |
296 | } | |
297 | ||
298 | /* Build a mask of the instruction's 'constant' opcode, | |
299 | based on the instruction's printing flags. */ | |
300 | ||
301 | static unsigned long | |
302 | build_mask (void) | |
303 | { | |
304 | unsigned int print_flags; | |
305 | unsigned long mask; | |
306 | ||
307 | print_flags = instruction->flags & FMT_CRX; | |
308 | switch (print_flags) | |
309 | { | |
310 | case FMT_1: | |
311 | mask = 0xF0F00000; | |
312 | break; | |
313 | case FMT_2: | |
314 | mask = 0xFFF0FF00; | |
315 | break; | |
316 | case FMT_3: | |
317 | mask = 0xFFF00F00; | |
318 | break; | |
319 | case FMT_4: | |
320 | mask = 0xFFF0F000; | |
321 | break; | |
322 | case FMT_5: | |
323 | mask = 0xFFF0FFF0; | |
324 | break; | |
325 | default: | |
326 | mask = SBM(instruction->match_bits); | |
327 | break; | |
328 | } | |
329 | ||
330 | return mask; | |
331 | } | |
332 | ||
333 | /* Search for a matching opcode. Return 1 for success, 0 for failure. */ | |
334 | ||
335 | static int | |
336 | match_opcode (void) | |
337 | { | |
338 | unsigned long mask; | |
339 | ||
340 | /* The instruction 'constant' opcode doewsn't exceed 32 bits. */ | |
341 | unsigned long doubleWord = words[1] + (words[0] << 16); | |
342 | ||
343 | /* Start searching from end of instruction table. */ | |
344 | instruction = &crx_instruction[NUMOPCODES - 2]; | |
345 | ||
346 | /* Loop over instruction table until a full match is found. */ | |
347 | while (instruction >= crx_instruction) | |
348 | { | |
349 | mask = build_mask (); | |
350 | if ((doubleWord & mask) == BIN(instruction->match, instruction->match_bits)) | |
351 | return 1; | |
352 | else | |
353 | instruction--; | |
354 | } | |
355 | return 0; | |
356 | } | |
357 | ||
358 | /* Set the proper parameter value for different type of arguments. */ | |
359 | ||
360 | static void | |
361 | make_argument (argument * a, int start_bits) | |
362 | { | |
363 | int inst_bit_size, total_size; | |
364 | parameter p; | |
365 | ||
366 | if ((instruction->size == 3) && a->size >= 16) | |
367 | inst_bit_size = 48; | |
368 | else | |
369 | inst_bit_size = 32; | |
370 | ||
371 | switch (a->type) | |
372 | { | |
373 | case arg_copr: | |
374 | case arg_copsr: | |
375 | p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | |
376 | inst_bit_size - start_bits); | |
377 | a->cr = p.val; | |
378 | break; | |
379 | ||
380 | case arg_r: | |
381 | p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | |
382 | inst_bit_size - start_bits); | |
383 | a->r = p.val; | |
384 | break; | |
385 | ||
386 | case arg_ic: | |
387 | p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | |
388 | inst_bit_size - start_bits); | |
389 | ||
390 | if ((p.nbits == 4) && cst4flag) | |
391 | { | |
392 | if (IS_INSN_TYPE (CMPBR_INS) && (p.val == ESCAPE_16_BIT)) | |
393 | { | |
394 | /* A special case, where the value is actually stored | |
395 | in the last 4 bits. */ | |
396 | p = makelongparameter (allWords, 44, 48); | |
397 | /* The size of the instruction should be incremented. */ | |
398 | size_changed = 1; | |
399 | } | |
400 | ||
401 | if (p.val == 6) | |
402 | p.val = -1; | |
403 | else if (p.val == 13) | |
404 | p.val = 48; | |
405 | else if (p.val == 5) | |
406 | p.val = -4; | |
407 | else if (p.val == 10) | |
408 | p.val = 32; | |
409 | else if (p.val == 11) | |
410 | p.val = 20; | |
411 | else if (p.val == 9) | |
412 | p.val = 16; | |
413 | } | |
414 | ||
415 | a->constant = p.val; | |
416 | break; | |
417 | ||
418 | case arg_icr: | |
419 | a->scale = 0; | |
420 | total_size = a->size + 10; /* sizeof(rbase + ridx + scl2) = 10. */ | |
421 | p = makelongparameter (allWords, inst_bit_size - total_size, | |
422 | inst_bit_size - (total_size - 4)); | |
423 | a->r = p.val; | |
424 | p = makelongparameter (allWords, inst_bit_size - (total_size - 4), | |
425 | inst_bit_size - (total_size - 8)); | |
426 | a->i_r = p.val; | |
427 | p = makelongparameter (allWords, inst_bit_size - (total_size - 8), | |
428 | inst_bit_size - (total_size - 10)); | |
429 | a->scale = p.val; | |
430 | p = makelongparameter (allWords, inst_bit_size - (total_size - 10), | |
431 | inst_bit_size); | |
432 | a->constant = p.val; | |
433 | break; | |
434 | ||
435 | case arg_rbase: | |
436 | p = makelongparameter (allWords, inst_bit_size - (start_bits + 4), | |
437 | inst_bit_size - start_bits); | |
438 | a->r = p.val; | |
439 | break; | |
440 | ||
441 | case arg_cr: | |
442 | if (a->size <= 8) | |
443 | { | |
444 | p = makelongparameter (allWords, inst_bit_size - (start_bits + 4), | |
445 | inst_bit_size - start_bits); | |
446 | a->r = p.val; | |
447 | /* Case for opc4 r dispu rbase. */ | |
448 | p = makelongparameter (allWords, inst_bit_size - (start_bits + 8), | |
449 | inst_bit_size - (start_bits + 4)); | |
450 | } | |
451 | else | |
452 | { | |
453 | /* The 'rbase' start_bits is always relative to a 32-bit data type. */ | |
454 | p = makelongparameter (allWords, 32 - (start_bits + 4), | |
455 | 32 - start_bits); | |
456 | a->r = p.val; | |
457 | p = makelongparameter (allWords, 32 - start_bits, | |
458 | inst_bit_size); | |
459 | } | |
460 | if ((p.nbits == 4) && cst4flag) | |
461 | { | |
462 | if (instruction->flags & DISPUW4) | |
463 | p.val *= 2; | |
464 | else if (instruction->flags & DISPUD4) | |
465 | p.val *= 4; | |
466 | } | |
467 | a->constant = p.val; | |
468 | break; | |
469 | ||
470 | case arg_c: | |
471 | p = makelongparameter (allWords, inst_bit_size - (start_bits + a->size), | |
472 | inst_bit_size - start_bits); | |
473 | a->constant = p.val; | |
474 | break; | |
475 | default: | |
476 | break; | |
477 | } | |
478 | } | |
479 | ||
480 | /* Print a single argument. */ | |
481 | ||
482 | static void | |
483 | print_arg (argument *a, struct disassemble_info *info) | |
484 | { | |
485 | LONGLONG longdisp, mask; | |
486 | char sign_flag; | |
487 | int op_index = 0; | |
488 | char string[200]; | |
489 | PTR stream = info->stream; | |
490 | fprintf_ftype func = info->fprintf_func; | |
491 | ||
492 | switch (a->type) | |
493 | { | |
494 | case arg_copr: | |
495 | func (stream, "%s", getcopregname (a->cr, CRX_C_REGTYPE)); | |
496 | break; | |
497 | ||
498 | case arg_copsr: | |
499 | func (stream, "%s", getcopregname (a->cr, CRX_CS_REGTYPE)); | |
500 | break; | |
501 | ||
502 | case arg_r: | |
503 | if (IS_INSN_MNEMONIC ("mtpr") || IS_INSN_MNEMONIC ("mfpr")) | |
504 | func (stream, "%s", getprocregname (a->r)); | |
505 | else | |
506 | func (stream, "%s", getregname (a->r)); | |
507 | break; | |
508 | ||
509 | case arg_ic: | |
510 | if (IS_INSN_MNEMONIC ("excp")) | |
511 | func (stream, "%s", gettrapstring (a->constant)); | |
512 | ||
513 | else if (IS_INSN_MNEMONIC ("cinv")) | |
514 | func (stream, "%s", getcinvstring (a->constant)); | |
515 | ||
516 | else if (INST_HAS_REG_LIST) | |
517 | { | |
48c9f030 NC |
518 | COP_ARG_TYPE cop_ins = IS_INSN_TYPE (COP_REG_INS) ? |
519 | COP_ARG : IS_INSN_TYPE (COPS_REG_INS) ? | |
520 | COPS_ARG : NO_COP_ARG; | |
521 | ||
522 | if (cop_ins != NO_COP_ARG) | |
523 | { | |
524 | /* Check for proper argument number. */ | |
525 | if (processing_argument_number == 2) | |
526 | { | |
527 | getregliststring (a->constant, string, cop_ins); | |
528 | func (stream, "%s", string); | |
529 | } | |
530 | else | |
531 | func (stream, "$0x%x", a->constant); | |
532 | } | |
533 | else | |
1fe1f39c | 534 | { |
48c9f030 | 535 | getregliststring (a->constant, string, cop_ins); |
1fe1f39c NC |
536 | func (stream, "%s", string); |
537 | } | |
1fe1f39c NC |
538 | } |
539 | else | |
540 | func (stream, "$0x%x", a->constant); | |
541 | break; | |
542 | ||
543 | case arg_icr: | |
544 | func (stream, "0x%x(%s,%s,%d)", a->constant, getregname (a->r), | |
545 | getregname (a->i_r), powerof2 (a->scale)); | |
546 | break; | |
547 | ||
548 | case arg_rbase: | |
549 | func (stream, "(%s)", getregname (a->r)); | |
550 | break; | |
551 | ||
552 | case arg_cr: | |
553 | func (stream, "0x%x(%s)", a->constant, getregname (a->r)); | |
554 | ||
555 | if (IS_INSN_TYPE (LD_STOR_INS_INC)) | |
556 | func (stream, "+"); | |
557 | break; | |
558 | ||
559 | case arg_c: | |
560 | /* Removed the *2 part as because implicit zeros are no more required. | |
561 | Have to fix this as this needs a bit of extension in terms of branchins. | |
562 | Have to add support for cmp and branch instructions. */ | |
563 | if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal") | |
564 | || IS_INSN_TYPE (CMPBR_INS) || IS_INSN_TYPE (DCR_BRANCH_INS) | |
565 | || IS_INSN_TYPE (COP_BRANCH_INS)) | |
566 | { | |
567 | func (stream, "%c", '*'); | |
568 | longdisp = a->constant; | |
569 | longdisp <<= 1; | |
570 | sign_flag = '+'; | |
571 | ||
572 | switch (a->size) | |
573 | { | |
574 | case 8: | |
575 | case 16: | |
576 | case 24: | |
577 | case 32: | |
578 | mask = ((LONGLONG)1 << a->size) - 1; | |
579 | if (longdisp & ((LONGLONG)1 << a->size)) | |
580 | { | |
581 | sign_flag = '-'; | |
582 | longdisp = ~(longdisp) + 1; | |
583 | } | |
584 | a->constant = (unsigned long int) (longdisp & mask); | |
585 | break; | |
586 | default: | |
587 | func (stream, | |
588 | "Wrong offset used in branch/bal instruction"); | |
589 | break; | |
590 | } | |
591 | ||
592 | func (stream, "%c", sign_flag); | |
593 | } | |
594 | /* For branch Neq instruction it is 2*offset + 2. */ | |
595 | if (IS_INSN_TYPE (BRANCH_NEQ_INS)) | |
596 | a->constant = 2 * a->constant + 2; | |
597 | if (IS_INSN_TYPE (LD_STOR_INS_INC) | |
598 | || IS_INSN_TYPE (LD_STOR_INS) | |
599 | || IS_INSN_TYPE (STOR_IMM_INS) | |
600 | || IS_INSN_TYPE (CSTBIT_INS)) | |
601 | { | |
602 | op_index = instruction->flags & REVERSE_MATCH ? 0 : 1; | |
603 | if (instruction->operands[op_index].op_type == abs16) | |
604 | a->constant |= 0xFFFF0000; | |
605 | } | |
606 | func (stream, "0x%x", a->constant); | |
607 | break; | |
608 | default: | |
609 | break; | |
610 | } | |
611 | } | |
612 | ||
613 | /* Print all the arguments of CURRINSN instruction. */ | |
614 | ||
615 | static void | |
616 | print_arguments (ins *currInsn, struct disassemble_info *info) | |
617 | { | |
618 | int i; | |
619 | ||
620 | for (i = 0; i < currInsn->nargs; i++) | |
621 | { | |
622 | processing_argument_number = i; | |
623 | ||
624 | print_arg (&currInsn->arg[i], info); | |
625 | ||
626 | if (i != currInsn->nargs - 1) | |
627 | info->fprintf_func (info->stream, ", "); | |
628 | } | |
629 | } | |
630 | ||
631 | /* Build the instruction's arguments. */ | |
632 | ||
633 | static void | |
634 | make_instruction (void) | |
635 | { | |
636 | int i; | |
637 | unsigned int temp_value, shift; | |
638 | argument a; | |
639 | ||
640 | for (i = 0; i < currInsn.nargs; i++) | |
641 | { | |
642 | a.type = getargtype (instruction->operands[i].op_type); | |
643 | if (instruction->operands[i].op_type == cst4 | |
644 | || instruction->operands[i].op_type == rbase_cst4) | |
645 | cst4flag = 1; | |
646 | a.size = getbits (instruction->operands[i].op_type); | |
647 | shift = instruction->operands[i].shift; | |
648 | ||
649 | make_argument (&a, shift); | |
650 | currInsn.arg[i] = a; | |
651 | } | |
652 | ||
653 | /* Calculate instruction size (in bytes). */ | |
654 | currInsn.size = instruction->size + (size_changed ? 1 : 0); | |
655 | currInsn.size *= 2; | |
656 | ||
657 | /* Swapping first and second arguments. */ | |
658 | if (IS_INSN_TYPE (COP_BRANCH_INS)) | |
659 | { | |
660 | temp_value = currInsn.arg[0].constant; | |
661 | currInsn.arg[0].constant = currInsn.arg[1].constant; | |
662 | currInsn.arg[1].constant = temp_value; | |
663 | } | |
664 | } | |
665 | ||
666 | /* Retrieve a single word from a given memory address. */ | |
667 | ||
668 | static wordU | |
669 | get_word_at_PC (bfd_vma memaddr, struct disassemble_info *info) | |
670 | { | |
671 | bfd_byte buffer[4]; | |
672 | int status; | |
673 | wordU insn = 0; | |
674 | ||
675 | status = info->read_memory_func (memaddr, buffer, 2, info); | |
676 | ||
677 | if (status == 0) | |
678 | insn = (wordU) bfd_getl16 (buffer); | |
679 | ||
680 | return insn; | |
681 | } | |
682 | ||
683 | /* Retrieve multiple words (3) from a given memory address. */ | |
684 | ||
685 | static void | |
686 | get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info) | |
687 | { | |
688 | int i; | |
689 | bfd_vma mem; | |
690 | ||
691 | for (i = 0, mem = memaddr; i < 3; i++, mem += 2) | |
692 | words[i] = get_word_at_PC (mem, info); | |
693 | ||
694 | allWords = | |
695 | ((ULONGLONG) words[0] << 32) + ((unsigned long) words[1] << 16) + words[2]; | |
696 | } | |
697 | ||
698 | /* Prints the instruction by calling print_arguments after proper matching. */ | |
699 | ||
700 | int | |
701 | print_insn_crx (memaddr, info) | |
702 | bfd_vma memaddr; | |
703 | struct disassemble_info *info; | |
704 | { | |
705 | int is_decoded; /* Nonzero means instruction has a match. */ | |
706 | ||
707 | /* Initialize global variables. */ | |
708 | cst4flag = 0; | |
709 | size_changed = 0; | |
710 | ||
711 | /* Retrieve the encoding from current memory location. */ | |
712 | get_words_at_PC (memaddr, info); | |
713 | /* Find a matching opcode in table. */ | |
714 | is_decoded = match_opcode (); | |
715 | /* If found, print the instruction's mnemonic and arguments. */ | |
716 | if (is_decoded > 0 && (words[0] << 16 || words[1]) != 0) | |
717 | { | |
718 | info->fprintf_func (info->stream, "%s", instruction->mnemonic); | |
719 | if ((currInsn.nargs = get_number_of_operands ()) != 0) | |
720 | info->fprintf_func (info->stream, "\t"); | |
721 | make_instruction (); | |
722 | print_arguments (&currInsn, info); | |
723 | return currInsn.size; | |
724 | } | |
725 | ||
726 | /* No match found. */ | |
727 | info->fprintf_func (info->stream,"%s ",ILLEGAL); | |
728 | return 2; | |
729 | } |