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