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