/src/binutils-gdb/opcodes/cr16-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Disassembler code for CR16. |
2 | | Copyright (C) 2007-2023 Free Software Foundation, Inc. |
3 | | Contributed by M R Swami Reddy (MR.Swami.Reddy@nsc.com). |
4 | | |
5 | | This file is part of GAS, GDB and the GNU binutils. |
6 | | |
7 | | This program is free software; you can redistribute it and/or modify it |
8 | | under the terms of the GNU General Public License as published by the |
9 | | Free Software Foundation; either version 3, or (at your option) |
10 | | any later version. |
11 | | |
12 | | This program is distributed in the hope that it will be useful, but WITHOUT |
13 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 | | more details. |
16 | | |
17 | | You should have received a copy of the GNU General Public License |
18 | | along with this program; if not, write to the Free Software Foundation, |
19 | | Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
20 | | |
21 | | #include "sysdep.h" |
22 | | #include "disassemble.h" |
23 | | #include "opcode/cr16.h" |
24 | | #include "libiberty.h" |
25 | | |
26 | | /* String to print when opcode was not matched. */ |
27 | 21.0k | #define ILLEGAL "illegal" |
28 | | /* Escape to 16-bit immediate. */ |
29 | | #define ESCAPE_16_BIT 0xB |
30 | | |
31 | | /* Extract 'n_bits' from 'a' starting from offset 'offs'. */ |
32 | | #define EXTRACT(a, offs, n_bits) \ |
33 | 272k | (((a) >> (offs)) & ((1ul << ((n_bits) - 1) << 1) - 1)) |
34 | | |
35 | | /* Set Bit Mask - a mask to set all bits in a 32-bit word starting |
36 | | from offset 'offs'. */ |
37 | 24.5M | #define SBM(offs) ((1ul << 31 << 1) - (1ul << (offs))) |
38 | | |
39 | | /* Structure to map valid 'cinv' instruction options. */ |
40 | | |
41 | | typedef struct |
42 | | { |
43 | | /* Cinv printed string. */ |
44 | | char *istr; |
45 | | /* Value corresponding to the string. */ |
46 | | char *ostr; |
47 | | } |
48 | | cinv_entry; |
49 | | |
50 | | /* CR16 'cinv' options mapping. */ |
51 | | static const cinv_entry cr16_cinvs[] = |
52 | | { |
53 | | {"cinv[i]", "cinv [i]"}, |
54 | | {"cinv[i,u]", "cinv [i,u]"}, |
55 | | {"cinv[d]", "cinv [d]"}, |
56 | | {"cinv[d,u]", "cinv [d,u]"}, |
57 | | {"cinv[d,i]", "cinv [d,i]"}, |
58 | | {"cinv[d,i,u]", "cinv [d,i,u]"} |
59 | | }; |
60 | | |
61 | | /* Number of valid 'cinv' instruction options. */ |
62 | | static int NUMCINVS = ARRAY_SIZE (cr16_cinvs); |
63 | | |
64 | | /* Enum to distinguish different registers argument types. */ |
65 | | typedef enum REG_ARG_TYPE |
66 | | { |
67 | | /* General purpose register (r<N>). */ |
68 | | REG_ARG = 0, |
69 | | /*Processor register */ |
70 | | P_ARG, |
71 | | } |
72 | | REG_ARG_TYPE; |
73 | | |
74 | | /* Current opcode table entry we're disassembling. */ |
75 | | static const inst *instruction; |
76 | | /* Current instruction we're disassembling. */ |
77 | | static ins cr16_currInsn; |
78 | | /* The current instruction is read into 3 consecutive words. */ |
79 | | static wordU cr16_words[3]; |
80 | | /* Contains all words in appropriate order. */ |
81 | | static ULONGLONG cr16_allWords; |
82 | | /* Holds the current processed argument number. */ |
83 | | static int processing_argument_number; |
84 | | /* Nonzero means a IMM4 instruction. */ |
85 | | static int imm4flag; |
86 | | /* Nonzero means the instruction's original size is |
87 | | incremented (escape sequence is used). */ |
88 | | static int size_changed; |
89 | | |
90 | | |
91 | | /* Print the constant expression length. */ |
92 | | |
93 | | static char * |
94 | | print_exp_len (int size) |
95 | 69.5k | { |
96 | 69.5k | switch (size) |
97 | 69.5k | { |
98 | 0 | case 4: |
99 | 0 | case 5: |
100 | 0 | case 6: |
101 | 0 | case 8: |
102 | 0 | case 14: |
103 | 45.4k | case 16: |
104 | 45.4k | return ":s"; |
105 | 0 | case 20: |
106 | 0 | case 24: |
107 | 23.6k | case 32: |
108 | 23.6k | return ":m"; |
109 | 454 | case 48: |
110 | 454 | return ":l"; |
111 | 0 | default: |
112 | 0 | return ""; |
113 | 69.5k | } |
114 | 69.5k | } |
115 | | |
116 | | |
117 | | /* Retrieve the number of operands for the current assembled instruction. */ |
118 | | |
119 | | static int |
120 | | get_number_of_operands (void) |
121 | 113k | { |
122 | 113k | int i; |
123 | | |
124 | 335k | for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++) |
125 | 221k | ; |
126 | | |
127 | 113k | return i; |
128 | 113k | } |
129 | | |
130 | | /* Return the bit size for a given operand. */ |
131 | | |
132 | | static int |
133 | | getbits (operand_type op) |
134 | 221k | { |
135 | 221k | if (op < MAX_OPRD) |
136 | 221k | return cr16_optab[op].bit_size; |
137 | | |
138 | 0 | return 0; |
139 | 221k | } |
140 | | |
141 | | /* Return the argument type of a given operand. */ |
142 | | |
143 | | static argtype |
144 | | getargtype (operand_type op) |
145 | 221k | { |
146 | 221k | if (op < MAX_OPRD) |
147 | 221k | return cr16_optab[op].arg_type; |
148 | | |
149 | 0 | return nullargs; |
150 | 221k | } |
151 | | |
152 | | /* Given a 'CC' instruction constant operand, return its corresponding |
153 | | string. This routine is used when disassembling the 'CC' instruction. */ |
154 | | |
155 | | static char * |
156 | | getccstring (unsigned cc_insn) |
157 | 8.74k | { |
158 | 8.74k | return (char *) cr16_b_cond_tab[cc_insn]; |
159 | 8.74k | } |
160 | | |
161 | | |
162 | | /* Given a 'cinv' instruction constant operand, return its corresponding |
163 | | string. This routine is used when disassembling the 'cinv' instruction. */ |
164 | | |
165 | | static char * |
166 | | getcinvstring (const char *str) |
167 | 390 | { |
168 | 390 | const cinv_entry *cinv; |
169 | | |
170 | 1.49k | for (cinv = cr16_cinvs; cinv < (cr16_cinvs + NUMCINVS); cinv++) |
171 | 1.49k | if (strcmp (cinv->istr, str) == 0) |
172 | 390 | return cinv->ostr; |
173 | | |
174 | 0 | return ILLEGAL; |
175 | 390 | } |
176 | | |
177 | | /* Given the trap index in dispatch table, return its name. |
178 | | This routine is used when disassembling the 'excp' instruction. */ |
179 | | |
180 | | static char * |
181 | | gettrapstring (unsigned int trap_index) |
182 | 500 | { |
183 | 500 | const trap_entry *trap; |
184 | | |
185 | 4.19k | for (trap = cr16_traps; trap < cr16_traps + NUMTRAPS; trap++) |
186 | 3.92k | if (trap->entry == trap_index) |
187 | 222 | return trap->name; |
188 | | |
189 | 278 | return ILLEGAL; |
190 | 500 | } |
191 | | |
192 | | /* Given a register enum value, retrieve its name. */ |
193 | | |
194 | | static char * |
195 | | getregname (reg r) |
196 | 78.3k | { |
197 | 78.3k | const reg_entry * regentry = cr16_regtab + r; |
198 | | |
199 | 78.3k | if (regentry->type != CR16_R_REGTYPE) |
200 | 0 | return ILLEGAL; |
201 | | |
202 | 78.3k | return regentry->name; |
203 | 78.3k | } |
204 | | |
205 | | /* Given a register pair enum value, retrieve its name. */ |
206 | | |
207 | | static char * |
208 | | getregpname (reg r) |
209 | 65.3k | { |
210 | 65.3k | const reg_entry * regentry = cr16_regptab + r; |
211 | | |
212 | 65.3k | if (regentry->type != CR16_RP_REGTYPE) |
213 | 0 | return ILLEGAL; |
214 | | |
215 | 65.3k | return regentry->name; |
216 | 65.3k | } |
217 | | |
218 | | /* Given a index register pair enum value, retrieve its name. */ |
219 | | |
220 | | static char * |
221 | | getidxregpname (reg r) |
222 | 5.22k | { |
223 | 5.22k | const reg_entry * regentry; |
224 | | |
225 | 5.22k | switch (r) |
226 | 5.22k | { |
227 | 1.05k | case 0: r = 0; break; |
228 | 520 | case 1: r = 2; break; |
229 | 672 | case 2: r = 4; break; |
230 | 239 | case 3: r = 6; break; |
231 | 513 | case 4: r = 8; break; |
232 | 174 | case 5: r = 10; break; |
233 | 1.80k | case 6: r = 3; break; |
234 | 242 | case 7: r = 5; break; |
235 | 0 | default: |
236 | 0 | break; |
237 | 5.22k | } |
238 | | |
239 | 5.22k | regentry = cr16_regptab + r; |
240 | | |
241 | 5.22k | if (regentry->type != CR16_RP_REGTYPE) |
242 | 0 | return ILLEGAL; |
243 | | |
244 | 5.22k | return regentry->name; |
245 | 5.22k | } |
246 | | |
247 | | /* Getting a processor register name. */ |
248 | | |
249 | | static char * |
250 | | getprocregname (int reg_index) |
251 | 131 | { |
252 | 131 | const reg_entry *r; |
253 | | |
254 | 384 | for (r = cr16_pregtab; r < cr16_pregtab + NUMPREGS; r++) |
255 | 384 | if (r->image == reg_index) |
256 | 131 | return r->name; |
257 | | |
258 | 0 | return "ILLEGAL REGISTER"; |
259 | 131 | } |
260 | | |
261 | | /* Getting a processor register name - 32 bit size. */ |
262 | | |
263 | | static char * |
264 | | getprocpregname (int reg_index) |
265 | 19 | { |
266 | 19 | const reg_entry *r; |
267 | | |
268 | 141 | for (r = cr16_pregptab; r < cr16_pregptab + NUMPREGPS; r++) |
269 | 130 | if (r->image == reg_index) |
270 | 8 | return r->name; |
271 | | |
272 | 11 | return "ILLEGAL REGISTER"; |
273 | 19 | } |
274 | | |
275 | | /* START and END are relating 'cr16_allWords' struct, which is 48 bits size. |
276 | | |
277 | | START|--------|END |
278 | | +---------+---------+---------+---------+ |
279 | | | | V | A | L | |
280 | | +---------+---------+---------+---------+ |
281 | | 0 16 32 48 |
282 | | words [0] [1] [2] */ |
283 | | |
284 | | static inline dwordU |
285 | | makelongparameter (ULONGLONG val, int start, int end) |
286 | 272k | { |
287 | 272k | return EXTRACT (val, 48 - end, end - start); |
288 | 272k | } |
289 | | |
290 | | /* Build a mask of the instruction's 'constant' opcode, |
291 | | based on the instruction's printing flags. */ |
292 | | |
293 | | static unsigned long |
294 | | build_mask (void) |
295 | 24.5M | { |
296 | 24.5M | unsigned long mask = SBM (instruction->match_bits); |
297 | | |
298 | | /* Adjust mask for bcond with 32-bit size instruction. */ |
299 | 24.5M | if ((IS_INSN_MNEMONIC("b") && instruction->size == 2)) |
300 | 64.2k | mask = 0xff0f0000; |
301 | | |
302 | 24.5M | return mask; |
303 | 24.5M | } |
304 | | |
305 | | /* Search for a matching opcode. Return 1 for success, 0 for failure. */ |
306 | | |
307 | | int |
308 | | cr16_match_opcode (void) |
309 | 134k | { |
310 | 134k | unsigned long mask; |
311 | | /* The instruction 'constant' opcode doesn't exceed 32 bits. */ |
312 | 134k | unsigned long doubleWord = cr16_words[1] + ((unsigned) cr16_words[0] << 16); |
313 | | |
314 | | /* Start searching from end of instruction table. */ |
315 | 134k | instruction = &cr16_instruction[NUMOPCODES - 2]; |
316 | | |
317 | | /* Loop over instruction table until a full match is found. */ |
318 | 24.5M | while (instruction >= cr16_instruction) |
319 | 24.5M | { |
320 | 24.5M | mask = build_mask (); |
321 | | |
322 | 24.5M | if ((doubleWord & mask) == BIN (instruction->match, |
323 | 24.5M | instruction->match_bits)) |
324 | 113k | return 1; |
325 | 24.4M | else |
326 | 24.4M | instruction--; |
327 | 24.5M | } |
328 | 20.7k | return 0; |
329 | 134k | } |
330 | | |
331 | | /* Set the proper parameter value for different type of arguments. */ |
332 | | |
333 | | static void |
334 | | make_argument (argument * a, int start_bits) |
335 | 221k | { |
336 | 221k | int inst_bit_size; |
337 | 221k | dwordU p; |
338 | | |
339 | 221k | if ((instruction->size == 3) && a->size >= 16) |
340 | 3.49k | inst_bit_size = 48; |
341 | 218k | else |
342 | 218k | inst_bit_size = 32; |
343 | | |
344 | 221k | switch (a->type) |
345 | 221k | { |
346 | 77.6k | case arg_r: |
347 | 77.6k | p = makelongparameter (cr16_allWords, |
348 | 77.6k | inst_bit_size - (start_bits + a->size), |
349 | 77.6k | inst_bit_size - start_bits); |
350 | 77.6k | a->r = p; |
351 | 77.6k | break; |
352 | | |
353 | 26.0k | case arg_rp: |
354 | 26.0k | p = makelongparameter (cr16_allWords, |
355 | 26.0k | inst_bit_size - (start_bits + a->size), |
356 | 26.0k | inst_bit_size - start_bits); |
357 | 26.0k | a->rp = p; |
358 | 26.0k | break; |
359 | | |
360 | 131 | case arg_pr: |
361 | 131 | p = makelongparameter (cr16_allWords, |
362 | 131 | inst_bit_size - (start_bits + a->size), |
363 | 131 | inst_bit_size - start_bits); |
364 | 131 | a->pr = p; |
365 | 131 | break; |
366 | | |
367 | 19 | case arg_prp: |
368 | 19 | p = makelongparameter (cr16_allWords, |
369 | 19 | inst_bit_size - (start_bits + a->size), |
370 | 19 | inst_bit_size - start_bits); |
371 | 19 | a->prp = p; |
372 | 19 | break; |
373 | | |
374 | 40.1k | case arg_ic: |
375 | 40.1k | p = makelongparameter (cr16_allWords, |
376 | 40.1k | inst_bit_size - (start_bits + a->size), |
377 | 40.1k | inst_bit_size - start_bits); |
378 | 40.1k | a->constant = p; |
379 | 40.1k | break; |
380 | | |
381 | 8.74k | case arg_cc: |
382 | 8.74k | p = makelongparameter (cr16_allWords, |
383 | 8.74k | inst_bit_size - (start_bits + a->size), |
384 | 8.74k | inst_bit_size - start_bits); |
385 | 8.74k | a->cc = p; |
386 | 8.74k | break; |
387 | | |
388 | 8.14k | case arg_idxr: |
389 | 8.14k | if (IS_INSN_TYPE (CSTBIT_INS) && instruction->mnemonic[4] == 'b') |
390 | 1.34k | p = makelongparameter (cr16_allWords, 8, 9); |
391 | 6.80k | else |
392 | 6.80k | p = makelongparameter (cr16_allWords, 9, 10); |
393 | 8.14k | a->i_r = p; |
394 | 8.14k | p = makelongparameter (cr16_allWords, |
395 | 8.14k | inst_bit_size - a->size, inst_bit_size); |
396 | 8.14k | a->constant = p; |
397 | 8.14k | break; |
398 | | |
399 | 5.22k | case arg_idxrp: |
400 | 5.22k | p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 13); |
401 | 5.22k | a->i_r = p; |
402 | 5.22k | p = makelongparameter (cr16_allWords, start_bits + 13, start_bits + 16); |
403 | 5.22k | a->rp = p; |
404 | 5.22k | if (inst_bit_size > 32) |
405 | 144 | { |
406 | 144 | p = makelongparameter (cr16_allWords, inst_bit_size - start_bits - 12, |
407 | 144 | inst_bit_size); |
408 | 144 | a->constant = (p & 0xffff) | (p >> 8 & 0xf0000); |
409 | 144 | } |
410 | 5.07k | else if (instruction->size == 2) |
411 | 574 | { |
412 | 574 | p = makelongparameter (cr16_allWords, inst_bit_size - 22, |
413 | 574 | inst_bit_size); |
414 | 574 | a->constant = ((p & 0xf) | (((p >> 20) & 0x3) << 4) |
415 | 574 | | ((p >> 14 & 0x3) << 6) | (((p >>7) & 0x1f) << 7)); |
416 | 574 | } |
417 | 4.50k | else if (instruction->size == 1 && a->size == 0) |
418 | 4.50k | a->constant = 0; |
419 | | |
420 | 5.22k | break; |
421 | | |
422 | 0 | case arg_rbase: |
423 | 0 | p = makelongparameter (cr16_allWords, inst_bit_size, inst_bit_size); |
424 | 0 | a->constant = p; |
425 | 0 | p = makelongparameter (cr16_allWords, inst_bit_size - (start_bits + 4), |
426 | 0 | inst_bit_size - start_bits); |
427 | 0 | a->r = p; |
428 | 0 | break; |
429 | | |
430 | 91 | case arg_cr: |
431 | 91 | p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 16); |
432 | 91 | a->r = p; |
433 | 91 | p = makelongparameter (cr16_allWords, inst_bit_size - 28, inst_bit_size); |
434 | 91 | a->constant = ((p >> 8) & 0xf0000) | (p & 0xffff); |
435 | 91 | break; |
436 | | |
437 | 39.7k | case arg_crp: |
438 | 39.7k | if (instruction->size == 1) |
439 | 29.7k | p = makelongparameter (cr16_allWords, 12, 16); |
440 | 10.0k | else |
441 | 10.0k | p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 16); |
442 | 39.7k | a->rp = p; |
443 | | |
444 | 39.7k | if (inst_bit_size > 32) |
445 | 89 | { |
446 | 89 | p = makelongparameter (cr16_allWords, inst_bit_size - start_bits - 12, |
447 | 89 | inst_bit_size); |
448 | 89 | a->constant = ((p & 0xffff) | (p >> 8 & 0xf0000)); |
449 | 89 | } |
450 | 39.7k | else if (instruction->size == 2) |
451 | 9.95k | { |
452 | 9.95k | p = makelongparameter (cr16_allWords, inst_bit_size - 16, |
453 | 9.95k | inst_bit_size); |
454 | 9.95k | a->constant = p; |
455 | 9.95k | } |
456 | 29.7k | else if (instruction->size == 1 && a->size != 0) |
457 | 26.3k | { |
458 | 26.3k | p = makelongparameter (cr16_allWords, 4, 8); |
459 | 26.3k | if (IS_INSN_MNEMONIC ("loadw") |
460 | 26.3k | || IS_INSN_MNEMONIC ("loadd") |
461 | 26.3k | || IS_INSN_MNEMONIC ("storw") |
462 | 26.3k | || IS_INSN_MNEMONIC ("stord")) |
463 | 15.7k | a->constant = p * 2; |
464 | 10.6k | else |
465 | 10.6k | a->constant = p; |
466 | 26.3k | } |
467 | 3.37k | else /* below case for 0x0(reg pair) */ |
468 | 3.37k | a->constant = 0; |
469 | | |
470 | 39.7k | break; |
471 | | |
472 | 15.6k | case arg_c: |
473 | | |
474 | 15.6k | if ((IS_INSN_TYPE (BRANCH_INS)) |
475 | 15.6k | || (IS_INSN_MNEMONIC ("bal")) |
476 | 15.6k | || (IS_INSN_TYPE (CSTBIT_INS)) |
477 | 15.6k | || (IS_INSN_TYPE (LD_STOR_INS))) |
478 | 13.4k | { |
479 | 13.4k | switch (a->size) |
480 | 13.4k | { |
481 | 8.30k | case 8 : |
482 | 8.30k | p = makelongparameter (cr16_allWords, 0, start_bits); |
483 | 8.30k | a->constant = ((p & 0xf00) >> 4) | (p & 0xf); |
484 | 8.30k | break; |
485 | | |
486 | 1.16k | case 24: |
487 | 1.16k | if (instruction->size == 3) |
488 | 130 | { |
489 | 130 | p = makelongparameter (cr16_allWords, 16, inst_bit_size); |
490 | 130 | a->constant = ((((p >> 16) & 0xf) << 20) |
491 | 130 | | (((p >> 24) & 0xf) << 16) |
492 | 130 | | (p & 0xffff)); |
493 | 130 | } |
494 | 1.03k | else if (instruction->size == 2) |
495 | 1.03k | { |
496 | 1.03k | p = makelongparameter (cr16_allWords, 8, inst_bit_size); |
497 | 1.03k | a->constant = p; |
498 | 1.03k | } |
499 | 1.16k | break; |
500 | | |
501 | 3.96k | default: |
502 | 3.96k | p = makelongparameter (cr16_allWords, |
503 | 3.96k | inst_bit_size - (start_bits + a->size), |
504 | 3.96k | inst_bit_size - start_bits); |
505 | 3.96k | a->constant = p; |
506 | 3.96k | break; |
507 | 13.4k | } |
508 | 13.4k | } |
509 | 2.20k | else |
510 | 2.20k | { |
511 | 2.20k | p = makelongparameter (cr16_allWords, |
512 | 2.20k | inst_bit_size - (start_bits + a->size), |
513 | 2.20k | inst_bit_size - start_bits); |
514 | 2.20k | a->constant = p; |
515 | 2.20k | } |
516 | 15.6k | break; |
517 | | |
518 | 15.6k | default: |
519 | 0 | break; |
520 | 221k | } |
521 | 221k | } |
522 | | |
523 | | /* Print a single argument. */ |
524 | | |
525 | | static void |
526 | | print_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info) |
527 | 221k | { |
528 | 221k | LONGLONG longdisp, mask; |
529 | 221k | int sign_flag = 0; |
530 | 221k | int relative = 0; |
531 | 221k | bfd_vma number; |
532 | 221k | void *stream = info->stream; |
533 | 221k | fprintf_ftype func = info->fprintf_func; |
534 | | |
535 | 221k | switch (a->type) |
536 | 221k | { |
537 | 78.2k | case arg_r: |
538 | 78.2k | func (stream, "%s", getregname (a->r)); |
539 | 78.2k | break; |
540 | | |
541 | 25.0k | case arg_rp: |
542 | 25.0k | func (stream, "%s", getregpname (a->rp)); |
543 | 25.0k | break; |
544 | | |
545 | 131 | case arg_pr: |
546 | 131 | func (stream, "%s", getprocregname (a->pr)); |
547 | 131 | break; |
548 | | |
549 | 19 | case arg_prp: |
550 | 19 | func (stream, "%s", getprocpregname (a->prp)); |
551 | 19 | break; |
552 | | |
553 | 8.74k | case arg_cc: |
554 | 8.74k | func (stream, "%s", getccstring (a->cc)); |
555 | 8.74k | func (stream, "%s", "\t"); |
556 | 8.74k | break; |
557 | | |
558 | 40.1k | case arg_ic: |
559 | 40.1k | if (IS_INSN_MNEMONIC ("excp")) |
560 | 500 | { |
561 | 500 | func (stream, "%s", gettrapstring (a->constant)); |
562 | 500 | break; |
563 | 500 | } |
564 | 39.6k | else if ((IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS)) |
565 | 39.6k | && ((instruction->size == 1) && (a->constant == 9))) |
566 | 325 | func (stream, "$%d", -1); |
567 | 39.3k | else if (INST_HAS_REG_LIST) |
568 | 5.57k | func (stream, "$0x%lx", a->constant +1); |
569 | 33.7k | else if (IS_INSN_TYPE (SHIFT_INS)) |
570 | 4.76k | { |
571 | 4.76k | longdisp = a->constant; |
572 | 4.76k | mask = ((LONGLONG)1 << a->size) - 1; |
573 | 4.76k | if (longdisp & ((LONGLONG)1 << (a->size -1))) |
574 | 2.94k | { |
575 | 2.94k | sign_flag = 1; |
576 | 2.94k | longdisp = ~(longdisp) + 1; |
577 | 2.94k | } |
578 | 4.76k | a->constant = (unsigned long int) (longdisp & mask); |
579 | 4.76k | func (stream, "$%d", ((int)(sign_flag ? -a->constant : |
580 | 4.76k | a->constant))); |
581 | 4.76k | } |
582 | 28.9k | else |
583 | 28.9k | func (stream, "$0x%lx", a->constant); |
584 | 39.6k | switch (a->size) |
585 | 39.6k | { |
586 | 25.4k | case 4 : case 5 : case 6 : case 8 : |
587 | 25.4k | func (stream, "%s", ":s"); break; |
588 | 2.30k | case 16 : case 20 : func (stream, "%s", ":m"); break; |
589 | 3.04k | case 24 : case 32 : func (stream, "%s", ":l"); break; |
590 | 8.84k | default: break; |
591 | 39.6k | } |
592 | 39.6k | break; |
593 | | |
594 | 39.6k | case arg_idxr: |
595 | 8.21k | if (a->i_r == 0) func (stream, "[r12]"); |
596 | 8.21k | if (a->i_r == 1) func (stream, "[r13]"); |
597 | 8.21k | func (stream, "0x%lx", a->constant); |
598 | 8.21k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
599 | 8.21k | break; |
600 | | |
601 | 5.22k | case arg_idxrp: |
602 | 5.22k | if (a->i_r == 0) func (stream, "[r12]"); |
603 | 5.22k | if (a->i_r == 1) func (stream, "[r13]"); |
604 | 5.22k | func (stream, "0x%lx", a->constant); |
605 | 5.22k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
606 | 5.22k | func (stream, "%s", getidxregpname (a->rp)); |
607 | 5.22k | break; |
608 | | |
609 | 0 | case arg_rbase: |
610 | 0 | func (stream, "(%s)", getregname (a->r)); |
611 | 0 | break; |
612 | | |
613 | 117 | case arg_cr: |
614 | 117 | func (stream, "0x%lx", a->constant); |
615 | 117 | func (stream, "%s", print_exp_len (instruction->size * 16)); |
616 | 117 | func (stream, "(%s)", getregname (a->r)); |
617 | 117 | break; |
618 | | |
619 | 40.2k | case arg_crp: |
620 | 40.2k | func (stream, "0x%lx", a->constant); |
621 | 40.2k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
622 | 40.2k | func (stream, "%s", getregpname (a->rp)); |
623 | 40.2k | break; |
624 | | |
625 | 15.7k | case arg_c: |
626 | | /*Removed the *2 part as because implicit zeros are no more required. |
627 | | Have to fix this as this needs a bit of extension in terms of branch |
628 | | instructions. */ |
629 | 15.7k | if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal")) |
630 | 9.80k | { |
631 | 9.80k | relative = 1; |
632 | 9.80k | longdisp = a->constant; |
633 | | /* REVISIT: To sync with WinIDEA and CR16 4.1tools, the below |
634 | | line commented */ |
635 | | /* longdisp <<= 1; */ |
636 | 9.80k | mask = ((LONGLONG)1 << a->size) - 1; |
637 | 9.80k | switch (a->size) |
638 | 9.80k | { |
639 | 8.30k | case 8 : |
640 | 8.30k | { |
641 | 8.30k | longdisp <<= 1; |
642 | 8.30k | if (longdisp & ((LONGLONG)1 << a->size)) |
643 | 4.20k | { |
644 | 4.20k | sign_flag = 1; |
645 | 4.20k | longdisp = ~(longdisp) + 1; |
646 | 4.20k | } |
647 | 8.30k | break; |
648 | 0 | } |
649 | 350 | case 16 : |
650 | 1.49k | case 24 : |
651 | 1.49k | { |
652 | 1.49k | if (longdisp & 1) |
653 | 472 | { |
654 | 472 | sign_flag = 1; |
655 | 472 | longdisp = ~(longdisp) + 1; |
656 | 472 | } |
657 | 1.49k | break; |
658 | 350 | } |
659 | 0 | default: |
660 | 0 | func (stream, "Wrong offset used in branch/bal instruction"); |
661 | 0 | break; |
662 | 9.80k | } |
663 | 9.80k | a->constant = (unsigned long int) (longdisp & mask); |
664 | 9.80k | } |
665 | | /* For branch Neq instruction it is 2*offset + 2. */ |
666 | 5.99k | else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) |
667 | 2.20k | a->constant = 2 * a->constant + 2; |
668 | | |
669 | 15.7k | if ((!IS_INSN_TYPE (CSTBIT_INS)) && (!IS_INSN_TYPE (LD_STOR_INS))) |
670 | 12.1k | (sign_flag) ? func (stream, "%s", "*-"): func (stream, "%s","*+"); |
671 | | |
672 | | /* PR 10173: Avoid printing the 0x prefix twice. */ |
673 | 15.7k | if (info->symtab_size > 0) |
674 | 0 | func (stream, "%s", "0x"); |
675 | 15.7k | number = ((relative ? memaddr : 0) + |
676 | 15.7k | (sign_flag ? ((- a->constant) & 0xffffffe) : a->constant)); |
677 | | |
678 | 15.7k | (*info->print_address_func) ((number & ((1 << 24) - 1)), info); |
679 | | |
680 | 15.7k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
681 | 15.7k | break; |
682 | | |
683 | 0 | default: |
684 | 0 | break; |
685 | 221k | } |
686 | 221k | } |
687 | | |
688 | | /* Print all the arguments of CURRINSN instruction. */ |
689 | | |
690 | | static void |
691 | | print_arguments (ins *currentInsn, bfd_vma memaddr, struct disassemble_info *info) |
692 | 113k | { |
693 | 113k | int i; |
694 | | |
695 | | /* For "pop/push/popret RA instruction only. */ |
696 | 113k | if ((IS_INSN_MNEMONIC ("pop") |
697 | 113k | || (IS_INSN_MNEMONIC ("popret") |
698 | 112k | || (IS_INSN_MNEMONIC ("push")))) |
699 | 113k | && currentInsn->nargs == 1) |
700 | 18 | { |
701 | 18 | info->fprintf_func (info->stream, "RA"); |
702 | 18 | return; |
703 | 18 | } |
704 | | |
705 | 337k | for (i = 0; i < currentInsn->nargs; i++) |
706 | 223k | { |
707 | 223k | processing_argument_number = i; |
708 | | |
709 | | /* For "bal (ra), disp17" instruction only. */ |
710 | 223k | if ((IS_INSN_MNEMONIC ("bal")) && (i == 0) && instruction->size == 2) |
711 | 1.03k | { |
712 | 1.03k | info->fprintf_func (info->stream, "(ra),"); |
713 | 1.03k | continue; |
714 | 1.03k | } |
715 | | |
716 | 222k | if ((INST_HAS_REG_LIST) && (i == 2)) |
717 | 1.00k | info->fprintf_func (info->stream, "RA"); |
718 | 221k | else |
719 | 221k | print_arg (¤tInsn->arg[i], memaddr, info); |
720 | | |
721 | 222k | if ((i != currentInsn->nargs - 1) && (!IS_INSN_MNEMONIC ("b"))) |
722 | 101k | info->fprintf_func (info->stream, ","); |
723 | 222k | } |
724 | 113k | } |
725 | | |
726 | | /* Build the instruction's arguments. */ |
727 | | |
728 | | void |
729 | | cr16_make_instruction (void) |
730 | 113k | { |
731 | 113k | int i; |
732 | 113k | unsigned int shift; |
733 | | |
734 | 335k | for (i = 0; i < cr16_currInsn.nargs; i++) |
735 | 221k | { |
736 | 221k | argument a; |
737 | | |
738 | 221k | memset (&a, 0, sizeof (a)); |
739 | 221k | a.type = getargtype (instruction->operands[i].op_type); |
740 | 221k | a.size = getbits (instruction->operands[i].op_type); |
741 | 221k | shift = instruction->operands[i].shift; |
742 | | |
743 | 221k | make_argument (&a, shift); |
744 | 221k | cr16_currInsn.arg[i] = a; |
745 | 221k | } |
746 | | |
747 | | /* Calculate instruction size (in bytes). */ |
748 | 113k | cr16_currInsn.size = instruction->size + (size_changed ? 1 : 0); |
749 | | /* Now in bits. */ |
750 | 113k | cr16_currInsn.size *= 2; |
751 | 113k | } |
752 | | |
753 | | /* Retrieve a single word from a given memory address. */ |
754 | | |
755 | | static wordU |
756 | | get_word_at_PC (bfd_vma memaddr, struct disassemble_info *info) |
757 | 402k | { |
758 | 402k | bfd_byte buffer[4]; |
759 | 402k | int status; |
760 | 402k | wordU insn = 0; |
761 | | |
762 | 402k | status = info->read_memory_func (memaddr, buffer, 2, info); |
763 | | |
764 | 402k | if (status == 0) |
765 | 402k | insn = (wordU) bfd_getl16 (buffer); |
766 | | |
767 | 402k | return insn; |
768 | 402k | } |
769 | | |
770 | | /* Retrieve multiple words (3) from a given memory address. */ |
771 | | |
772 | | static void |
773 | | get_words_at_PC (bfd_vma memaddr, struct disassemble_info *info) |
774 | 134k | { |
775 | 134k | int i; |
776 | 134k | bfd_vma mem; |
777 | | |
778 | 537k | for (i = 0, mem = memaddr; i < 3; i++, mem += 2) |
779 | 402k | cr16_words[i] = get_word_at_PC (mem, info); |
780 | | |
781 | 134k | cr16_allWords = ((ULONGLONG) cr16_words[0] << 32) |
782 | 134k | + ((unsigned long) cr16_words[1] << 16) + cr16_words[2]; |
783 | 134k | } |
784 | | |
785 | | /* Prints the instruction by calling print_arguments after proper matching. */ |
786 | | |
787 | | int |
788 | | print_insn_cr16 (bfd_vma memaddr, struct disassemble_info *info) |
789 | 134k | { |
790 | 134k | int is_decoded; /* Nonzero means instruction has a match. */ |
791 | | |
792 | | /* Initialize global variables. */ |
793 | 134k | imm4flag = 0; |
794 | 134k | size_changed = 0; |
795 | | |
796 | | /* Retrieve the encoding from current memory location. */ |
797 | 134k | get_words_at_PC (memaddr, info); |
798 | | /* Find a matching opcode in table. */ |
799 | 134k | is_decoded = cr16_match_opcode (); |
800 | | /* If found, print the instruction's mnemonic and arguments. */ |
801 | 134k | if (is_decoded > 0 && (cr16_words[0] != 0 || cr16_words[1] != 0)) |
802 | 113k | { |
803 | 113k | if (startswith (instruction->mnemonic, "cinv")) |
804 | 390 | info->fprintf_func (info->stream,"%s", |
805 | 390 | getcinvstring (instruction->mnemonic)); |
806 | 113k | else |
807 | 113k | info->fprintf_func (info->stream, "%s", instruction->mnemonic); |
808 | | |
809 | 113k | if (((cr16_currInsn.nargs = get_number_of_operands ()) != 0) |
810 | 113k | && ! (IS_INSN_MNEMONIC ("b"))) |
811 | 103k | info->fprintf_func (info->stream, "\t"); |
812 | 113k | cr16_make_instruction (); |
813 | | /* For push/pop/pushrtn with RA instructions. */ |
814 | 113k | if ((INST_HAS_REG_LIST) && ((cr16_words[0] >> 7) & 0x1)) |
815 | 2.30k | cr16_currInsn.nargs +=1; |
816 | 113k | print_arguments (&cr16_currInsn, memaddr, info); |
817 | 113k | return cr16_currInsn.size; |
818 | 113k | } |
819 | | |
820 | | /* No match found. */ |
821 | 20.7k | info->fprintf_func (info->stream,"%s ",ILLEGAL); |
822 | 20.7k | return 2; |
823 | 134k | } |