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