/src/binutils-gdb/opcodes/cr16-dis.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Disassembler code for CR16. |
2 | | Copyright (C) 2007-2025 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 | 16.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 | 191k | (((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 | 18.2M | #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 | 47.0k | { |
96 | 47.0k | switch (size) |
97 | 47.0k | { |
98 | 0 | case 4: |
99 | 0 | case 5: |
100 | 0 | case 6: |
101 | 0 | case 8: |
102 | 0 | case 14: |
103 | 29.2k | case 16: |
104 | 29.2k | return ":s"; |
105 | 0 | case 20: |
106 | 0 | case 24: |
107 | 16.5k | case 32: |
108 | 16.5k | return ":m"; |
109 | 1.19k | case 48: |
110 | 1.19k | return ":l"; |
111 | 0 | default: |
112 | 0 | return ""; |
113 | 47.0k | } |
114 | 47.0k | } |
115 | | |
116 | | |
117 | | /* Retrieve the number of operands for the current assembled instruction. */ |
118 | | |
119 | | static int |
120 | | get_number_of_operands (void) |
121 | 80.9k | { |
122 | 80.9k | int i; |
123 | | |
124 | 237k | for (i = 0; instruction->operands[i].op_type && i < MAX_OPERANDS; i++) |
125 | 157k | ; |
126 | | |
127 | 80.9k | return i; |
128 | 80.9k | } |
129 | | |
130 | | /* Return the bit size for a given operand. */ |
131 | | |
132 | | static int |
133 | | getbits (operand_type op) |
134 | 157k | { |
135 | 157k | if (op < MAX_OPRD) |
136 | 157k | return cr16_optab[op].bit_size; |
137 | | |
138 | 0 | return 0; |
139 | 157k | } |
140 | | |
141 | | /* Return the argument type of a given operand. */ |
142 | | |
143 | | static argtype |
144 | | getargtype (operand_type op) |
145 | 157k | { |
146 | 157k | if (op < MAX_OPRD) |
147 | 157k | return cr16_optab[op].arg_type; |
148 | | |
149 | 0 | return nullargs; |
150 | 157k | } |
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 | 5.70k | { |
158 | 5.70k | return (char *) cr16_b_cond_tab[cc_insn]; |
159 | 5.70k | } |
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 | 375 | { |
168 | 375 | const cinv_entry *cinv; |
169 | | |
170 | 1.14k | for (cinv = cr16_cinvs; cinv < (cr16_cinvs + NUMCINVS); cinv++) |
171 | 1.14k | if (strcmp (cinv->istr, str) == 0) |
172 | 375 | return cinv->ostr; |
173 | | |
174 | 0 | return ILLEGAL; |
175 | 375 | } |
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 | 613 | { |
183 | 613 | const trap_entry *trap; |
184 | | |
185 | 4.84k | for (trap = cr16_traps; trap < cr16_traps + NUMTRAPS; trap++) |
186 | 4.60k | if (trap->entry == trap_index) |
187 | 379 | return trap->name; |
188 | | |
189 | 234 | return ILLEGAL; |
190 | 613 | } |
191 | | |
192 | | /* Given a register enum value, retrieve its name. */ |
193 | | |
194 | | static char * |
195 | | getregname (reg r) |
196 | 57.0k | { |
197 | 57.0k | const reg_entry * regentry = cr16_regtab + r; |
198 | | |
199 | 57.0k | if (regentry->type != CR16_R_REGTYPE) |
200 | 0 | return ILLEGAL; |
201 | | |
202 | 57.0k | return regentry->name; |
203 | 57.0k | } |
204 | | |
205 | | /* Given a register pair enum value, retrieve its name. */ |
206 | | |
207 | | static char * |
208 | | getregpname (reg r) |
209 | 44.1k | { |
210 | 44.1k | const reg_entry * regentry = cr16_regptab + r; |
211 | | |
212 | 44.1k | if (regentry->type != CR16_RP_REGTYPE) |
213 | 0 | return ILLEGAL; |
214 | | |
215 | 44.1k | return regentry->name; |
216 | 44.1k | } |
217 | | |
218 | | /* Given a index register pair enum value, retrieve its name. */ |
219 | | |
220 | | static char * |
221 | | getidxregpname (reg r) |
222 | 2.81k | { |
223 | 2.81k | const reg_entry * regentry; |
224 | | |
225 | 2.81k | switch (r) |
226 | 2.81k | { |
227 | 350 | case 0: r = 0; break; |
228 | 105 | case 1: r = 2; break; |
229 | 443 | case 2: r = 4; break; |
230 | 289 | case 3: r = 6; break; |
231 | 200 | case 4: r = 8; break; |
232 | 69 | case 5: r = 10; break; |
233 | 1.20k | case 6: r = 3; break; |
234 | 160 | case 7: r = 5; break; |
235 | 0 | default: |
236 | 0 | break; |
237 | 2.81k | } |
238 | | |
239 | 2.81k | regentry = cr16_regptab + r; |
240 | | |
241 | 2.81k | if (regentry->type != CR16_RP_REGTYPE) |
242 | 0 | return ILLEGAL; |
243 | | |
244 | 2.81k | return regentry->name; |
245 | 2.81k | } |
246 | | |
247 | | /* Getting a processor register name. */ |
248 | | |
249 | | static char * |
250 | | getprocregname (int reg_index) |
251 | 99 | { |
252 | 99 | const reg_entry *r; |
253 | | |
254 | 442 | for (r = cr16_pregtab; r < cr16_pregtab + NUMPREGS; r++) |
255 | 442 | if (r->image == reg_index) |
256 | 99 | return r->name; |
257 | | |
258 | 0 | return "ILLEGAL REGISTER"; |
259 | 99 | } |
260 | | |
261 | | /* Getting a processor register name - 32 bit size. */ |
262 | | |
263 | | static char * |
264 | | getprocpregname (int reg_index) |
265 | 141 | { |
266 | 141 | const reg_entry *r; |
267 | | |
268 | 1.05k | for (r = cr16_pregptab; r < cr16_pregptab + NUMPREGPS; r++) |
269 | 991 | if (r->image == reg_index) |
270 | 81 | return r->name; |
271 | | |
272 | 60 | return "ILLEGAL REGISTER"; |
273 | 141 | } |
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 | 191k | { |
287 | 191k | return EXTRACT (val, 48 - end, end - start); |
288 | 191k | } |
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 | 18.2M | { |
296 | 18.2M | unsigned long mask = SBM (instruction->match_bits); |
297 | | |
298 | | /* Adjust mask for bcond with 32-bit size instruction. */ |
299 | 18.2M | if ((IS_INSN_MNEMONIC("b") && instruction->size == 2)) |
300 | 46.3k | mask = 0xff0f0000; |
301 | | |
302 | 18.2M | return mask; |
303 | 18.2M | } |
304 | | |
305 | | /* Search for a matching opcode. Return 1 for success, 0 for failure. */ |
306 | | |
307 | | int |
308 | | cr16_match_opcode (void) |
309 | 96.7k | { |
310 | 96.7k | unsigned long mask; |
311 | | /* The instruction 'constant' opcode doesn't exceed 32 bits. */ |
312 | 96.7k | unsigned long doubleWord = cr16_words[1] + ((unsigned) cr16_words[0] << 16); |
313 | | |
314 | | /* Start searching from end of instruction table. */ |
315 | 96.7k | instruction = &cr16_instruction[NUMOPCODES - 2]; |
316 | | |
317 | | /* Loop over instruction table until a full match is found. */ |
318 | 18.2M | while (instruction >= cr16_instruction) |
319 | 18.2M | { |
320 | 18.2M | mask = build_mask (); |
321 | | |
322 | 18.2M | if ((doubleWord & mask) == BIN (instruction->match, |
323 | 18.2M | instruction->match_bits)) |
324 | 80.9k | return 1; |
325 | 18.1M | else |
326 | 18.1M | instruction--; |
327 | 18.2M | } |
328 | 15.8k | return 0; |
329 | 96.7k | } |
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 | 157k | { |
336 | 157k | int inst_bit_size; |
337 | 157k | dwordU p; |
338 | | |
339 | 157k | if ((instruction->size == 3) && a->size >= 16) |
340 | 3.55k | inst_bit_size = 48; |
341 | 153k | else |
342 | 153k | inst_bit_size = 32; |
343 | | |
344 | 157k | switch (a->type) |
345 | 157k | { |
346 | 56.6k | case arg_r: |
347 | 56.6k | p = makelongparameter (cr16_allWords, |
348 | 56.6k | inst_bit_size - (start_bits + a->size), |
349 | 56.6k | inst_bit_size - start_bits); |
350 | 56.6k | a->r = p; |
351 | 56.6k | break; |
352 | | |
353 | 17.9k | case arg_rp: |
354 | 17.9k | p = makelongparameter (cr16_allWords, |
355 | 17.9k | inst_bit_size - (start_bits + a->size), |
356 | 17.9k | inst_bit_size - start_bits); |
357 | 17.9k | a->rp = p; |
358 | 17.9k | break; |
359 | | |
360 | 99 | case arg_pr: |
361 | 99 | p = makelongparameter (cr16_allWords, |
362 | 99 | inst_bit_size - (start_bits + a->size), |
363 | 99 | inst_bit_size - start_bits); |
364 | 99 | a->pr = p; |
365 | 99 | break; |
366 | | |
367 | 126 | case arg_prp: |
368 | 126 | p = makelongparameter (cr16_allWords, |
369 | 126 | inst_bit_size - (start_bits + a->size), |
370 | 126 | inst_bit_size - start_bits); |
371 | 126 | a->prp = p; |
372 | 126 | break; |
373 | | |
374 | 29.7k | case arg_ic: |
375 | 29.7k | p = makelongparameter (cr16_allWords, |
376 | 29.7k | inst_bit_size - (start_bits + a->size), |
377 | 29.7k | inst_bit_size - start_bits); |
378 | 29.7k | a->constant = p; |
379 | 29.7k | break; |
380 | | |
381 | 5.70k | case arg_cc: |
382 | 5.70k | p = makelongparameter (cr16_allWords, |
383 | 5.70k | inst_bit_size - (start_bits + a->size), |
384 | 5.70k | inst_bit_size - start_bits); |
385 | 5.70k | a->cc = p; |
386 | 5.70k | break; |
387 | | |
388 | 5.65k | case arg_idxr: |
389 | 5.65k | if (IS_INSN_TYPE (CSTBIT_INS) && instruction->mnemonic[4] == 'b') |
390 | 939 | p = makelongparameter (cr16_allWords, 8, 9); |
391 | 4.71k | else |
392 | 4.71k | p = makelongparameter (cr16_allWords, 9, 10); |
393 | 5.65k | a->i_r = p; |
394 | 5.65k | p = makelongparameter (cr16_allWords, |
395 | 5.65k | inst_bit_size - a->size, inst_bit_size); |
396 | 5.65k | a->constant = p; |
397 | 5.65k | break; |
398 | | |
399 | 2.80k | case arg_idxrp: |
400 | 2.80k | p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 13); |
401 | 2.80k | a->i_r = p; |
402 | 2.80k | p = makelongparameter (cr16_allWords, start_bits + 13, start_bits + 16); |
403 | 2.80k | a->rp = p; |
404 | 2.80k | if (inst_bit_size > 32) |
405 | 263 | { |
406 | 263 | p = makelongparameter (cr16_allWords, inst_bit_size - start_bits - 12, |
407 | 263 | inst_bit_size); |
408 | 263 | a->constant = (p & 0xffff) | (p >> 8 & 0xf0000); |
409 | 263 | } |
410 | 2.53k | else if (instruction->size == 2) |
411 | 781 | { |
412 | 781 | p = makelongparameter (cr16_allWords, inst_bit_size - 22, |
413 | 781 | inst_bit_size); |
414 | 781 | a->constant = ((p & 0xf) | (((p >> 20) & 0x3) << 4) |
415 | 781 | | ((p >> 14 & 0x3) << 6) | (((p >>7) & 0x1f) << 7)); |
416 | 781 | } |
417 | 1.75k | else if (instruction->size == 1 && a->size == 0) |
418 | 1.75k | a->constant = 0; |
419 | | |
420 | 2.80k | 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 | 275 | case arg_cr: |
431 | 275 | p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 16); |
432 | 275 | a->r = p; |
433 | 275 | p = makelongparameter (cr16_allWords, inst_bit_size - 28, inst_bit_size); |
434 | 275 | a->constant = ((p >> 8) & 0xf0000) | (p & 0xffff); |
435 | 275 | break; |
436 | | |
437 | 26.6k | case arg_crp: |
438 | 26.6k | if (instruction->size == 1) |
439 | 19.9k | p = makelongparameter (cr16_allWords, 12, 16); |
440 | 6.73k | else |
441 | 6.73k | p = makelongparameter (cr16_allWords, start_bits + 12, start_bits + 16); |
442 | 26.6k | a->rp = p; |
443 | | |
444 | 26.6k | if (inst_bit_size > 32) |
445 | 111 | { |
446 | 111 | p = makelongparameter (cr16_allWords, inst_bit_size - start_bits - 12, |
447 | 111 | inst_bit_size); |
448 | 111 | a->constant = ((p & 0xffff) | (p >> 8 & 0xf0000)); |
449 | 111 | } |
450 | 26.5k | else if (instruction->size == 2) |
451 | 6.62k | { |
452 | 6.62k | p = makelongparameter (cr16_allWords, inst_bit_size - 16, |
453 | 6.62k | inst_bit_size); |
454 | 6.62k | a->constant = p; |
455 | 6.62k | } |
456 | 19.9k | else if (instruction->size == 1 && a->size != 0) |
457 | 18.1k | { |
458 | 18.1k | p = makelongparameter (cr16_allWords, 4, 8); |
459 | 18.1k | if (IS_INSN_MNEMONIC ("loadw") |
460 | 18.1k | || IS_INSN_MNEMONIC ("loadd") |
461 | 18.1k | || IS_INSN_MNEMONIC ("storw") |
462 | 18.1k | || IS_INSN_MNEMONIC ("stord")) |
463 | 11.3k | a->constant = p * 2; |
464 | 6.81k | else |
465 | 6.81k | a->constant = p; |
466 | 18.1k | } |
467 | 1.78k | else /* below case for 0x0(reg pair) */ |
468 | 1.78k | a->constant = 0; |
469 | | |
470 | 26.6k | break; |
471 | | |
472 | 11.3k | case arg_c: |
473 | | |
474 | 11.3k | if ((IS_INSN_TYPE (BRANCH_INS)) |
475 | 11.3k | || (IS_INSN_MNEMONIC ("bal")) |
476 | 11.3k | || (IS_INSN_TYPE (CSTBIT_INS)) |
477 | 11.3k | || (IS_INSN_TYPE (LD_STOR_INS))) |
478 | 9.27k | { |
479 | 9.27k | switch (a->size) |
480 | 9.27k | { |
481 | 5.18k | case 8 : |
482 | 5.18k | p = makelongparameter (cr16_allWords, 0, start_bits); |
483 | 5.18k | a->constant = ((p & 0xf00) >> 4) | (p & 0xf); |
484 | 5.18k | break; |
485 | | |
486 | 1.29k | case 24: |
487 | 1.29k | if (instruction->size == 3) |
488 | 550 | { |
489 | 550 | p = makelongparameter (cr16_allWords, 16, inst_bit_size); |
490 | 550 | a->constant = ((((p >> 16) & 0xf) << 20) |
491 | 550 | | (((p >> 24) & 0xf) << 16) |
492 | 550 | | (p & 0xffff)); |
493 | 550 | } |
494 | 740 | else if (instruction->size == 2) |
495 | 740 | { |
496 | 740 | p = makelongparameter (cr16_allWords, 8, inst_bit_size); |
497 | 740 | a->constant = p; |
498 | 740 | } |
499 | 1.29k | break; |
500 | | |
501 | 2.79k | default: |
502 | 2.79k | p = makelongparameter (cr16_allWords, |
503 | 2.79k | inst_bit_size - (start_bits + a->size), |
504 | 2.79k | inst_bit_size - start_bits); |
505 | 2.79k | a->constant = p; |
506 | 2.79k | break; |
507 | 9.27k | } |
508 | 9.27k | } |
509 | 2.10k | else |
510 | 2.10k | { |
511 | 2.10k | p = makelongparameter (cr16_allWords, |
512 | 2.10k | inst_bit_size - (start_bits + a->size), |
513 | 2.10k | inst_bit_size - start_bits); |
514 | 2.10k | a->constant = p; |
515 | 2.10k | } |
516 | 11.3k | break; |
517 | | |
518 | 11.3k | default: |
519 | 0 | break; |
520 | 157k | } |
521 | 157k | } |
522 | | |
523 | | /* Print a single argument. */ |
524 | | |
525 | | static void |
526 | | print_arg (argument *a, bfd_vma memaddr, struct disassemble_info *info) |
527 | 156k | { |
528 | 156k | LONGLONG longdisp, mask; |
529 | 156k | int sign_flag = 0; |
530 | 156k | int relative = 0; |
531 | 156k | bfd_vma number; |
532 | 156k | void *stream = info->stream; |
533 | 156k | fprintf_ftype func = info->fprintf_func; |
534 | | |
535 | 156k | switch (a->type) |
536 | 156k | { |
537 | 56.7k | case arg_r: |
538 | 56.7k | func (stream, "%s", getregname (a->r)); |
539 | 56.7k | break; |
540 | | |
541 | 17.3k | case arg_rp: |
542 | 17.3k | func (stream, "%s", getregpname (a->rp)); |
543 | 17.3k | break; |
544 | | |
545 | 99 | case arg_pr: |
546 | 99 | func (stream, "%s", getprocregname (a->pr)); |
547 | 99 | break; |
548 | | |
549 | 141 | case arg_prp: |
550 | 141 | func (stream, "%s", getprocpregname (a->prp)); |
551 | 141 | break; |
552 | | |
553 | 5.70k | case arg_cc: |
554 | 5.70k | func (stream, "%s", getccstring (a->cc)); |
555 | 5.70k | func (stream, "%s", "\t"); |
556 | 5.70k | break; |
557 | | |
558 | 29.7k | case arg_ic: |
559 | 29.7k | if (IS_INSN_MNEMONIC ("excp")) |
560 | 613 | { |
561 | 613 | func (stream, "%s", gettrapstring (a->constant)); |
562 | 613 | break; |
563 | 613 | } |
564 | 29.1k | else if ((IS_INSN_TYPE (ARITH_INS) || IS_INSN_TYPE (ARITH_BYTE_INS)) |
565 | 29.1k | && ((instruction->size == 1) && (a->constant == 9))) |
566 | 333 | func (stream, "$%d", -1); |
567 | 28.7k | else if (INST_HAS_REG_LIST) |
568 | 4.75k | func (stream, "$0x%lx", a->constant +1); |
569 | 24.0k | else if (IS_INSN_TYPE (SHIFT_INS)) |
570 | 3.45k | { |
571 | 3.45k | longdisp = a->constant; |
572 | 3.45k | mask = ((LONGLONG)1 << a->size) - 1; |
573 | 3.45k | if (longdisp & ((LONGLONG)1 << (a->size -1))) |
574 | 2.15k | { |
575 | 2.15k | sign_flag = 1; |
576 | 2.15k | longdisp = ~(longdisp) + 1; |
577 | 2.15k | } |
578 | 3.45k | a->constant = (unsigned long int) (longdisp & mask); |
579 | 3.45k | func (stream, "$%d", ((int)(sign_flag ? -a->constant : |
580 | 3.45k | a->constant))); |
581 | 3.45k | } |
582 | 20.5k | else |
583 | 20.5k | func (stream, "$0x%lx", a->constant); |
584 | 29.1k | switch (a->size) |
585 | 29.1k | { |
586 | 18.3k | case 4 : case 5 : case 6 : case 8 : |
587 | 18.3k | func (stream, "%s", ":s"); break; |
588 | 1.30k | case 16 : case 20 : func (stream, "%s", ":m"); break; |
589 | 2.35k | case 24 : case 32 : func (stream, "%s", ":l"); break; |
590 | 7.14k | default: break; |
591 | 29.1k | } |
592 | 29.1k | break; |
593 | | |
594 | 29.1k | case arg_idxr: |
595 | 5.69k | if (a->i_r == 0) func (stream, "[r12]"); |
596 | 5.69k | if (a->i_r == 1) func (stream, "[r13]"); |
597 | 5.69k | func (stream, "0x%lx", a->constant); |
598 | 5.69k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
599 | 5.69k | break; |
600 | | |
601 | 2.81k | case arg_idxrp: |
602 | 2.81k | if (a->i_r == 0) func (stream, "[r12]"); |
603 | 2.81k | if (a->i_r == 1) func (stream, "[r13]"); |
604 | 2.81k | func (stream, "0x%lx", a->constant); |
605 | 2.81k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
606 | 2.81k | func (stream, "%s", getidxregpname (a->rp)); |
607 | 2.81k | break; |
608 | | |
609 | 0 | case arg_rbase: |
610 | 0 | func (stream, "(%s)", getregname (a->r)); |
611 | 0 | break; |
612 | | |
613 | 277 | case arg_cr: |
614 | 277 | func (stream, "0x%lx", a->constant); |
615 | 277 | func (stream, "%s", print_exp_len (instruction->size * 16)); |
616 | 277 | func (stream, "(%s)", getregname (a->r)); |
617 | 277 | break; |
618 | | |
619 | 26.8k | case arg_crp: |
620 | 26.8k | func (stream, "0x%lx", a->constant); |
621 | 26.8k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
622 | 26.8k | func (stream, "%s", getregpname (a->rp)); |
623 | 26.8k | break; |
624 | | |
625 | 11.4k | 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 | 11.4k | if (IS_INSN_TYPE (BRANCH_INS) || IS_INSN_MNEMONIC ("bal")) |
630 | 6.68k | { |
631 | 6.68k | relative = 1; |
632 | 6.68k | longdisp = a->constant; |
633 | | /* REVISIT: To sync with WinIDEA and CR16 4.1tools, the below |
634 | | line commented */ |
635 | | /* longdisp <<= 1; */ |
636 | 6.68k | mask = ((LONGLONG)1 << a->size) - 1; |
637 | 6.68k | switch (a->size) |
638 | 6.68k | { |
639 | 5.18k | case 8 : |
640 | 5.18k | { |
641 | 5.18k | longdisp <<= 1; |
642 | 5.18k | if (longdisp & ((LONGLONG)1 << a->size)) |
643 | 2.22k | { |
644 | 2.22k | sign_flag = 1; |
645 | 2.22k | longdisp = ~(longdisp) + 1; |
646 | 2.22k | } |
647 | 5.18k | break; |
648 | 0 | } |
649 | 237 | case 16 : |
650 | 1.50k | case 24 : |
651 | 1.50k | { |
652 | 1.50k | if (longdisp & 1) |
653 | 318 | { |
654 | 318 | sign_flag = 1; |
655 | 318 | longdisp = ~(longdisp) + 1; |
656 | 318 | } |
657 | 1.50k | break; |
658 | 237 | } |
659 | 0 | default: |
660 | 0 | func (stream, "Wrong offset used in branch/bal instruction"); |
661 | 0 | break; |
662 | 6.68k | } |
663 | 6.68k | a->constant = (unsigned long int) (longdisp & mask); |
664 | 6.68k | } |
665 | | /* For branch Neq instruction it is 2*offset + 2. */ |
666 | 4.75k | else if (IS_INSN_TYPE (BRANCH_NEQ_INS)) |
667 | 2.10k | a->constant = 2 * a->constant + 2; |
668 | | |
669 | 11.4k | if ((!IS_INSN_TYPE (CSTBIT_INS)) && (!IS_INSN_TYPE (LD_STOR_INS))) |
670 | 8.86k | (sign_flag) ? func (stream, "%s", "*-"): func (stream, "%s","*+"); |
671 | | |
672 | | /* PR 10173: Avoid printing the 0x prefix twice. */ |
673 | 11.4k | if (info->symtab_size > 0) |
674 | 0 | func (stream, "%s", "0x"); |
675 | 11.4k | number = ((relative ? memaddr : 0) + |
676 | 11.4k | (sign_flag ? ((- a->constant) & 0xffffffe) : a->constant)); |
677 | | |
678 | 11.4k | (*info->print_address_func) ((number & ((1 << 24) - 1)), info); |
679 | | |
680 | 11.4k | func (stream, "%s", print_exp_len (instruction->size * 16)); |
681 | 11.4k | break; |
682 | | |
683 | 0 | default: |
684 | 0 | break; |
685 | 156k | } |
686 | 156k | } |
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 | 80.9k | { |
693 | 80.9k | int i; |
694 | | |
695 | | /* For "pop/push/popret RA instruction only. */ |
696 | 80.9k | if ((IS_INSN_MNEMONIC ("pop") |
697 | 80.9k | || (IS_INSN_MNEMONIC ("popret") |
698 | 80.0k | || (IS_INSN_MNEMONIC ("push")))) |
699 | 80.9k | && currentInsn->nargs == 1) |
700 | 41 | { |
701 | 41 | info->fprintf_func (info->stream, "RA"); |
702 | 41 | return; |
703 | 41 | } |
704 | | |
705 | 239k | for (i = 0; i < currentInsn->nargs; i++) |
706 | 158k | { |
707 | 158k | processing_argument_number = i; |
708 | | |
709 | | /* For "bal (ra), disp17" instruction only. */ |
710 | 158k | if ((IS_INSN_MNEMONIC ("bal")) && (i == 0) && instruction->size == 2) |
711 | 740 | { |
712 | 740 | info->fprintf_func (info->stream, "(ra),"); |
713 | 740 | continue; |
714 | 740 | } |
715 | | |
716 | 157k | if ((INST_HAS_REG_LIST) && (i == 2)) |
717 | 857 | info->fprintf_func (info->stream, "RA"); |
718 | 156k | else |
719 | 156k | print_arg (¤tInsn->arg[i], memaddr, info); |
720 | | |
721 | 157k | if ((i != currentInsn->nargs - 1) && (!IS_INSN_MNEMONIC ("b"))) |
722 | 72.3k | info->fprintf_func (info->stream, ","); |
723 | 157k | } |
724 | 80.8k | } |
725 | | |
726 | | /* Build the instruction's arguments. */ |
727 | | |
728 | | void |
729 | | cr16_make_instruction (void) |
730 | 80.9k | { |
731 | 80.9k | int i; |
732 | 80.9k | unsigned int shift; |
733 | | |
734 | 237k | for (i = 0; i < cr16_currInsn.nargs; i++) |
735 | 157k | { |
736 | 157k | argument a; |
737 | | |
738 | 157k | memset (&a, 0, sizeof (a)); |
739 | 157k | a.type = getargtype (instruction->operands[i].op_type); |
740 | 157k | a.size = getbits (instruction->operands[i].op_type); |
741 | 157k | shift = instruction->operands[i].shift; |
742 | | |
743 | 157k | make_argument (&a, shift); |
744 | 157k | cr16_currInsn.arg[i] = a; |
745 | 157k | } |
746 | | |
747 | | /* Calculate instruction size (in bytes). */ |
748 | 80.9k | cr16_currInsn.size = instruction->size + (size_changed ? 1 : 0); |
749 | | /* Now in bits. */ |
750 | 80.9k | cr16_currInsn.size *= 2; |
751 | 80.9k | } |
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 | 290k | { |
758 | 290k | bfd_byte buffer[4]; |
759 | 290k | int status; |
760 | 290k | wordU insn = 0; |
761 | | |
762 | 290k | status = info->read_memory_func (memaddr, buffer, 2, info); |
763 | | |
764 | 290k | if (status == 0) |
765 | 289k | insn = (wordU) bfd_getl16 (buffer); |
766 | | |
767 | 290k | return insn; |
768 | 290k | } |
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 | 96.7k | { |
775 | 96.7k | int i; |
776 | 96.7k | bfd_vma mem; |
777 | | |
778 | 387k | for (i = 0, mem = memaddr; i < 3; i++, mem += 2) |
779 | 290k | cr16_words[i] = get_word_at_PC (mem, info); |
780 | | |
781 | 96.7k | cr16_allWords = ((ULONGLONG) cr16_words[0] << 32) |
782 | 96.7k | + ((unsigned long) cr16_words[1] << 16) + cr16_words[2]; |
783 | 96.7k | } |
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 | 96.7k | { |
790 | 96.7k | int is_decoded; /* Nonzero means instruction has a match. */ |
791 | | |
792 | | /* Initialize global variables. */ |
793 | 96.7k | imm4flag = 0; |
794 | 96.7k | size_changed = 0; |
795 | | |
796 | | /* Retrieve the encoding from current memory location. */ |
797 | 96.7k | get_words_at_PC (memaddr, info); |
798 | | /* Find a matching opcode in table. */ |
799 | 96.7k | is_decoded = cr16_match_opcode (); |
800 | | /* If found, print the instruction's mnemonic and arguments. */ |
801 | 96.7k | if (is_decoded > 0 && (cr16_words[0] != 0 || cr16_words[1] != 0)) |
802 | 80.9k | { |
803 | 80.9k | if (startswith (instruction->mnemonic, "cinv")) |
804 | 375 | info->fprintf_func (info->stream,"%s", |
805 | 375 | getcinvstring (instruction->mnemonic)); |
806 | 80.5k | else |
807 | 80.5k | info->fprintf_func (info->stream, "%s", instruction->mnemonic); |
808 | | |
809 | 80.9k | if (((cr16_currInsn.nargs = get_number_of_operands ()) != 0) |
810 | 80.9k | && ! (IS_INSN_MNEMONIC ("b"))) |
811 | 73.9k | info->fprintf_func (info->stream, "\t"); |
812 | 80.9k | cr16_make_instruction (); |
813 | | /* For push/pop/pushrtn with RA instructions. */ |
814 | 80.9k | if ((INST_HAS_REG_LIST) && ((cr16_words[0] >> 7) & 0x1)) |
815 | 1.43k | cr16_currInsn.nargs +=1; |
816 | 80.9k | print_arguments (&cr16_currInsn, memaddr, info); |
817 | 80.9k | return cr16_currInsn.size; |
818 | 80.9k | } |
819 | | |
820 | | /* No match found. */ |
821 | 15.8k | info->fprintf_func (info->stream,"%s ",ILLEGAL); |
822 | 15.8k | return 2; |
823 | 96.7k | } |