/src/binutils-gdb/opcodes/tic6x-dis.c
Line | Count | Source |
1 | | /* TI C6X disassembler. |
2 | | Copyright (C) 2010-2026 Free Software Foundation, Inc. |
3 | | Contributed by Joseph Myers <joseph@codesourcery.com> |
4 | | Bernd Schmidt <bernds@codesourcery.com> |
5 | | |
6 | | This file is part of libopcodes. |
7 | | |
8 | | This library is free software; you can redistribute it and/or modify |
9 | | it under the terms of the GNU General Public License as published by |
10 | | the Free Software Foundation; either version 3 of the License, or |
11 | | (at your option) any later version. |
12 | | |
13 | | It is distributed in the hope that it will be useful, but WITHOUT |
14 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
15 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
16 | | License for more details. |
17 | | |
18 | | You should have received a copy of the GNU General Public License |
19 | | along with this program; if not, write to the Free Software |
20 | | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
21 | | MA 02110-1301, USA. */ |
22 | | |
23 | | #include "sysdep.h" |
24 | | #include "disassemble.h" |
25 | | #include "opcode/tic6x.h" |
26 | | #include "libiberty.h" |
27 | | |
28 | | /* Define the instruction format table. */ |
29 | | const tic6x_insn_format tic6x_insn_format_table[tic6x_insn_format_max] = |
30 | | { |
31 | | #define FMT(name, num_bits, cst_bits, mask, fields) \ |
32 | | { num_bits, cst_bits, mask, fields }, |
33 | | #include "opcode/tic6x-insn-formats.h" |
34 | | #undef FMT |
35 | | }; |
36 | | |
37 | | /* Define the control register table. */ |
38 | | const tic6x_ctrl tic6x_ctrl_table[tic6x_ctrl_max] = |
39 | | { |
40 | | #define CTRL(name, isa, rw, crlo, crhi_mask) \ |
41 | | { \ |
42 | | STRINGX(name), \ |
43 | | CONCAT2(TIC6X_INSN_,isa), \ |
44 | | CONCAT2(tic6x_rw_,rw), \ |
45 | | crlo, \ |
46 | | crhi_mask \ |
47 | | }, |
48 | | #include "opcode/tic6x-control-registers.h" |
49 | | #undef CTRL |
50 | | }; |
51 | | |
52 | | /* Define the opcode table. */ |
53 | | const tic6x_opcode tic6x_opcode_table[tic6x_opcode_max] = |
54 | | { |
55 | | #define INSNU(name, func_unit, format, type, isa, flags, fixed, ops, var) \ |
56 | | { \ |
57 | | STRINGX(name), \ |
58 | | CONCAT2(tic6x_func_unit_,func_unit), \ |
59 | | CONCAT3(tic6x_insn_format,_,format), \ |
60 | | CONCAT2(tic6x_pipeline_,type), \ |
61 | | CONCAT2(TIC6X_INSN_,isa), \ |
62 | | flags, \ |
63 | | fixed, \ |
64 | | ops, \ |
65 | | var \ |
66 | | }, |
67 | | #define INSNUE(name, e, func_unit, format, type, isa, flags, fixed, ops, var) \ |
68 | | { \ |
69 | | STRINGX(name), \ |
70 | | CONCAT2(tic6x_func_unit_,func_unit), \ |
71 | | CONCAT3(tic6x_insn_format,_,format), \ |
72 | | CONCAT2(tic6x_pipeline_,type), \ |
73 | | CONCAT2(TIC6X_INSN_,isa), \ |
74 | | flags, \ |
75 | | fixed, \ |
76 | | ops, \ |
77 | | var \ |
78 | | }, |
79 | | #define INSN(name, func_unit, format, type, isa, flags, fixed, ops, var) \ |
80 | | { \ |
81 | | STRINGX(name), \ |
82 | | CONCAT2(tic6x_func_unit_,func_unit), \ |
83 | | CONCAT4(tic6x_insn_format_,func_unit,_,format), \ |
84 | | CONCAT2(tic6x_pipeline_,type), \ |
85 | | CONCAT2(TIC6X_INSN_,isa), \ |
86 | | flags, \ |
87 | | fixed, \ |
88 | | ops, \ |
89 | | var \ |
90 | | }, |
91 | | #define INSNE(name, e, func_unit, format, type, isa, flags, fixed, ops, var) \ |
92 | | { \ |
93 | | STRINGX(name), \ |
94 | | CONCAT2(tic6x_func_unit_,func_unit), \ |
95 | | CONCAT4(tic6x_insn_format_,func_unit,_,format), \ |
96 | | CONCAT2(tic6x_pipeline_,type), \ |
97 | | CONCAT2(TIC6X_INSN_,isa), \ |
98 | | flags, \ |
99 | | fixed, \ |
100 | | ops, \ |
101 | | var \ |
102 | | }, |
103 | | #include "opcode/tic6x-opcode-table.h" |
104 | | #undef INSN |
105 | | #undef INSNE |
106 | | #undef INSNU |
107 | | #undef INSNUE |
108 | | }; |
109 | | |
110 | | /* If instruction format FMT has a field FIELD, return a pointer to |
111 | | the description of that field; otherwise return NULL. */ |
112 | | |
113 | | const tic6x_insn_field * |
114 | | tic6x_field_from_fmt (const tic6x_insn_format *fmt, tic6x_insn_field_id field) |
115 | 12.8M | { |
116 | 12.8M | unsigned int f; |
117 | | |
118 | 46.1M | for (f = 0; f < fmt->num_fields; f++) |
119 | 46.1M | if (fmt->fields[f].field_id == field) |
120 | 12.7M | return &fmt->fields[f]; |
121 | | |
122 | 80.7k | return NULL; |
123 | 12.8M | } |
124 | | |
125 | | /* Extract the field width. */ |
126 | | |
127 | | static unsigned int |
128 | | tic6x_field_width (const tic6x_insn_field *field) |
129 | 39.4k | { |
130 | 39.4k | unsigned int i; |
131 | 39.4k | unsigned int width = 0; |
132 | | |
133 | 39.4k | if (!field->num_bitfields) |
134 | 0 | return field->bitfields[0].width; |
135 | | |
136 | 80.3k | for (i = 0 ; i < field->num_bitfields ; i++) |
137 | 40.8k | width += field->bitfields[i].width; |
138 | | |
139 | 39.4k | return width; |
140 | 39.4k | } |
141 | | |
142 | | /* Extract the bits corresponding to FIELD from OPCODE. */ |
143 | | |
144 | | static unsigned int |
145 | | tic6x_field_bits (unsigned int opcode, const tic6x_insn_field *field) |
146 | 12.7M | { |
147 | 12.7M | unsigned int i; |
148 | 12.7M | unsigned int val = 0; |
149 | | |
150 | 12.7M | if (!field->num_bitfields) |
151 | 0 | return (opcode >> field->bitfields[0].low_pos) & ((1u << field->bitfields[0].width) - 1); |
152 | | |
153 | 25.5M | for (i = 0 ; i < field->num_bitfields ; i++) |
154 | 12.7M | val |= ((opcode >> field->bitfields[i].low_pos) & ((1u << field->bitfields[i].width) - 1)) |
155 | 12.7M | << field->bitfields[i].pos; |
156 | | |
157 | 12.7M | return val; |
158 | 12.7M | } |
159 | | |
160 | | /* Extract a 32-bit value read from the instruction stream. */ |
161 | | |
162 | | static unsigned int |
163 | | tic6x_extract_32 (unsigned char *p, struct disassemble_info *info) |
164 | 658k | { |
165 | 658k | if (info->endian == BFD_ENDIAN_LITTLE) |
166 | 8.20k | return p[0] | (p[1] << 8) | (p[2] << 16) | ((unsigned) p[3] << 24); |
167 | 650k | else |
168 | 650k | return p[3] | (p[2] << 8) | (p[1] << 16) | ((unsigned) p[0] << 24); |
169 | 658k | } |
170 | | |
171 | | /* Extract a 16-bit value read from the instruction stream. */ |
172 | | |
173 | | static unsigned int |
174 | | tic6x_extract_16 (unsigned char *p, tic6x_fetch_packet_header *header, |
175 | | struct disassemble_info *info) |
176 | 20.6k | { |
177 | 20.6k | unsigned int op16; |
178 | | |
179 | 20.6k | if (info->endian == BFD_ENDIAN_LITTLE) |
180 | 109 | op16 = (p[0]) | (p[1] << 8); |
181 | 20.5k | else |
182 | 20.5k | op16 = (p[1]) | (p[0] << 8); |
183 | 20.6k | op16 |= (header->sat << TIC6X_COMPACT_SAT_POS); |
184 | 20.6k | op16 |= (header->br << TIC6X_COMPACT_BR_POS); |
185 | 20.6k | op16 |= (header->dsz << TIC6X_COMPACT_DSZ_POS); |
186 | 20.6k | return op16; |
187 | 20.6k | } |
188 | | |
189 | | /* FP points to a fetch packet. Return whether it is header-based; if |
190 | | it is, fill in HEADER. */ |
191 | | |
192 | | static bool |
193 | | tic6x_check_fetch_packet_header (unsigned char *fp, |
194 | | tic6x_fetch_packet_header *header, |
195 | | struct disassemble_info *info) |
196 | 256k | { |
197 | 256k | int i; |
198 | | |
199 | 256k | header->header = tic6x_extract_32 (fp + 28, info); |
200 | | |
201 | 256k | if ((header->header & 0xf0000000) != 0xe0000000) |
202 | 228k | { |
203 | 228k | header->prot = 0; |
204 | 228k | header->rs = 0; |
205 | 228k | header->dsz = 0; |
206 | 228k | header->br = 0; |
207 | 228k | header->sat = 0; |
208 | 1.82M | for (i = 0; i < 7; i++) |
209 | 1.60M | header->word_compact[i] = false; |
210 | 3.42M | for (i = 0; i < 14; i++) |
211 | 3.20M | header->p_bits[i] = false; |
212 | 228k | return false; |
213 | 228k | } |
214 | | |
215 | 224k | for (i = 0; i < 7; i++) |
216 | 196k | header->word_compact[i] |
217 | 196k | = (header->header & (1u << (21 + i))) != 0; |
218 | | |
219 | 28.0k | header->prot = (header->header & (1u << 20)) != 0; |
220 | 28.0k | header->rs = (header->header & (1u << 19)) != 0; |
221 | 28.0k | header->dsz = (header->header >> 16) & 0x7; |
222 | 28.0k | header->br = (header->header & (1u << 15)) != 0; |
223 | 28.0k | header->sat = (header->header & (1u << 14)) != 0; |
224 | | |
225 | 421k | for (i = 0; i < 14; i++) |
226 | 392k | header->p_bits[i] = (header->header & (1u << i)) != 0; |
227 | | |
228 | 28.0k | return true; |
229 | 256k | } |
230 | | |
231 | | /* Disassemble the instruction at ADDR and print it using |
232 | | INFO->FPRINTF_FUNC and INFO->STREAM, returning the number of bytes |
233 | | consumed. */ |
234 | | |
235 | | int |
236 | | print_insn_tic6x (bfd_vma addr, struct disassemble_info *info) |
237 | 230k | { |
238 | 230k | int status; |
239 | 230k | bfd_vma fp_addr; |
240 | 230k | bfd_vma fp_offset; |
241 | 230k | unsigned char fp[32]; |
242 | 230k | unsigned int opcode; |
243 | 230k | tic6x_opcode_id opcode_id; |
244 | 230k | bool fetch_packet_header_based; |
245 | 230k | tic6x_fetch_packet_header header; |
246 | 230k | unsigned int num_bits; |
247 | 230k | bool bad_offset = false; |
248 | | |
249 | 230k | fp_offset = addr & 0x1f; |
250 | 230k | fp_addr = addr - fp_offset; |
251 | | /* Read in a block of instructions. Since there might be a |
252 | | symbol in the middle of this block, disable stop_vma. */ |
253 | 230k | info->stop_vma = 0; |
254 | 230k | status = info->read_memory_func (fp_addr, fp, 32, info); |
255 | 230k | if (status) |
256 | 266 | { |
257 | 266 | info->memory_error_func (status, addr, info); |
258 | 266 | return -1; |
259 | 266 | } |
260 | | |
261 | 230k | fetch_packet_header_based |
262 | 230k | = tic6x_check_fetch_packet_header (fp, &header, info); |
263 | 230k | if (fetch_packet_header_based) |
264 | 26.5k | { |
265 | 26.5k | if (fp_offset & 0x1) |
266 | 10 | bad_offset = true; |
267 | 26.5k | else if ((fp_offset & 0x3) && (fp_offset >= 28 |
268 | 9.43k | || !header.word_compact[fp_offset >> 2])) |
269 | 10 | bad_offset = true; |
270 | 26.4k | else if (fp_offset == 28) |
271 | 2.15k | { |
272 | 2.15k | info->bytes_per_chunk = 4; |
273 | 2.15k | info->fprintf_func (info->stream, "<fetch packet header 0x%.8x>", |
274 | 2.15k | header.header); |
275 | 2.15k | return 4; |
276 | 2.15k | } |
277 | 26.5k | } |
278 | 203k | else |
279 | 203k | { |
280 | 203k | if (fp_offset & 0x3) |
281 | 4 | bad_offset = true; |
282 | 203k | } |
283 | | |
284 | 228k | if (bad_offset) |
285 | 24 | { |
286 | 24 | info->bytes_per_chunk = 1; |
287 | 24 | info->fprintf_func (info->stream, ".byte 0x%.2x", fp[fp_offset]); |
288 | 24 | return 1; |
289 | 24 | } |
290 | | |
291 | 228k | num_bits = 32; |
292 | 228k | if (fetch_packet_header_based && header.word_compact[fp_offset >> 2]) |
293 | 18.9k | num_bits = 16; |
294 | | |
295 | 228k | if (num_bits == 16) |
296 | 18.9k | { |
297 | | /* The least-significant part of a 32-bit word comes logically |
298 | | before the most-significant part. For big-endian, follow the |
299 | | TI assembler in showing instructions in logical order by |
300 | | pretending that the two halves of the word are in opposite |
301 | | locations to where they actually are. */ |
302 | 18.9k | if (info->endian == BFD_ENDIAN_LITTLE) |
303 | 109 | opcode = tic6x_extract_16 (fp + fp_offset, &header, info); |
304 | 18.7k | else |
305 | 18.7k | opcode = tic6x_extract_16 (fp + (fp_offset ^ 2), &header, info); |
306 | 18.9k | } |
307 | 209k | else |
308 | 209k | opcode = tic6x_extract_32 (fp + fp_offset, info); |
309 | | |
310 | 88.8M | for (opcode_id = 0; opcode_id < tic6x_opcode_max; opcode_id++) |
311 | 88.7M | { |
312 | 88.7M | const tic6x_opcode *const opc = &tic6x_opcode_table[opcode_id]; |
313 | 88.7M | const tic6x_insn_format *const fmt |
314 | 88.7M | = &tic6x_insn_format_table[opc->format]; |
315 | 88.7M | const tic6x_insn_field *creg_field; |
316 | 88.7M | bool p_bit; |
317 | 88.7M | const char *parallel; |
318 | 88.7M | const char *cond = ""; |
319 | 88.7M | const char *func_unit; |
320 | 88.7M | char func_unit_buf[8]; |
321 | 88.7M | unsigned int func_unit_side = 0; |
322 | 88.7M | unsigned int func_unit_data_side = 0; |
323 | 88.7M | unsigned int func_unit_cross = 0; |
324 | 88.7M | unsigned int t_val = 0; |
325 | | /* The maximum length of the text of a non-PC-relative operand |
326 | | is 24 bytes (SPMASK masking all eight functional units, with |
327 | | separating commas and trailing NUL). */ |
328 | 88.7M | char operands[TIC6X_MAX_OPERANDS][24] = { { 0 } }; |
329 | 88.7M | bfd_vma operands_addresses[TIC6X_MAX_OPERANDS] = { 0 }; |
330 | 88.7M | bool operands_text[TIC6X_MAX_OPERANDS] = { false }; |
331 | 88.7M | bool operands_pcrel[TIC6X_MAX_OPERANDS] = { false }; |
332 | 88.7M | unsigned int fix; |
333 | 88.7M | unsigned int num_operands; |
334 | 88.7M | unsigned int op_num; |
335 | 88.7M | bool fixed_ok; |
336 | 88.7M | bool operands_ok; |
337 | 88.7M | bool have_t = false; |
338 | | |
339 | 88.7M | if (opc->flags & TIC6X_FLAG_MACRO) |
340 | 9.41M | continue; |
341 | 79.3M | if (fmt->num_bits != num_bits) |
342 | 26.6M | continue; |
343 | 52.6M | if ((opcode & fmt->mask) != fmt->cst_bits) |
344 | 48.6M | continue; |
345 | | |
346 | | /* If the format has a creg field, it is only a candidate for a |
347 | | match if the creg and z fields have values indicating a valid |
348 | | condition; reserved values indicate either an instruction |
349 | | format without a creg field, or an invalid instruction. */ |
350 | 4.03M | creg_field = tic6x_field_from_fmt (fmt, tic6x_field_creg); |
351 | 4.03M | if (creg_field) |
352 | 3.95M | { |
353 | 3.95M | const tic6x_insn_field *z_field; |
354 | 3.95M | unsigned int creg_value, z_value; |
355 | 3.95M | static const char *const conds[8][2] = |
356 | 3.95M | { |
357 | 3.95M | { "", NULL }, |
358 | 3.95M | { "[b0] ", "[!b0] " }, |
359 | 3.95M | { "[b1] ", "[!b1] " }, |
360 | 3.95M | { "[b2] ", "[!b2] " }, |
361 | 3.95M | { "[a1] ", "[!a1] " }, |
362 | 3.95M | { "[a2] ", "[!a2] " }, |
363 | 3.95M | { "[a0] ", "[!a0] " }, |
364 | 3.95M | { NULL, NULL } |
365 | 3.95M | }; |
366 | | |
367 | | /* A creg field is not meaningful without a z field, so if |
368 | | the z field is not present this is an error in the format |
369 | | table. */ |
370 | 3.95M | z_field = tic6x_field_from_fmt (fmt, tic6x_field_z); |
371 | 3.95M | if (!z_field) |
372 | 0 | { |
373 | 0 | printf ("*** opcode %x: missing z field", opcode); |
374 | 0 | abort (); |
375 | 0 | } |
376 | | |
377 | 3.95M | creg_value = tic6x_field_bits (opcode, creg_field); |
378 | 3.95M | z_value = tic6x_field_bits (opcode, z_field); |
379 | 3.95M | cond = conds[creg_value][z_value]; |
380 | 3.95M | if (cond == NULL) |
381 | 680k | continue; |
382 | 3.95M | } |
383 | | |
384 | 3.35M | if (opc->flags & TIC6X_FLAG_INSN16_SPRED) |
385 | 6.43k | { |
386 | 6.43k | const tic6x_insn_field *cc_field; |
387 | 6.43k | unsigned int s_value = 0; |
388 | 6.43k | unsigned int z_value = 0; |
389 | 6.43k | bool cond_known = false; |
390 | 6.43k | static const char *const conds[2][2] = |
391 | 6.43k | { |
392 | 6.43k | { "[a0] ", "[!a0] " }, |
393 | 6.43k | { "[b0] ", "[!b0] " } |
394 | 6.43k | }; |
395 | | |
396 | 6.43k | cc_field = tic6x_field_from_fmt (fmt, tic6x_field_cc); |
397 | | |
398 | 6.43k | if (cc_field) |
399 | 241 | { |
400 | 241 | unsigned int cc_value; |
401 | | |
402 | 241 | cc_value = tic6x_field_bits (opcode, cc_field); |
403 | 241 | s_value = (cc_value & 0x2) >> 1; |
404 | 241 | z_value = (cc_value & 0x1); |
405 | 241 | cond_known = true; |
406 | 241 | } |
407 | 6.19k | else |
408 | 6.19k | { |
409 | 6.19k | const tic6x_insn_field *z_field; |
410 | 6.19k | const tic6x_insn_field *s_field; |
411 | | |
412 | 6.19k | s_field = tic6x_field_from_fmt (fmt, tic6x_field_s); |
413 | | |
414 | 6.19k | if (!s_field) |
415 | 0 | { |
416 | 0 | printf ("opcode %x: missing compact insn predicate register field (s field)\n", |
417 | 0 | opcode); |
418 | 0 | abort (); |
419 | 0 | } |
420 | 6.19k | s_value = tic6x_field_bits (opcode, s_field); |
421 | 6.19k | z_field = tic6x_field_from_fmt (fmt, tic6x_field_z); |
422 | 6.19k | if (!z_field) |
423 | 0 | { |
424 | 0 | printf ("opcode %x: missing compact insn predicate z_value (z field)\n", opcode); |
425 | 0 | abort (); |
426 | 0 | } |
427 | | |
428 | 6.19k | z_value = tic6x_field_bits (opcode, z_field); |
429 | 6.19k | cond_known = true; |
430 | 6.19k | } |
431 | | |
432 | 6.43k | if (!cond_known) |
433 | 0 | { |
434 | 0 | printf ("opcode %x: unspecified ompact insn predicate\n", opcode); |
435 | 0 | abort (); |
436 | 0 | } |
437 | 6.43k | cond = conds[s_value][z_value]; |
438 | 6.43k | } |
439 | | |
440 | | /* All fixed fields must have matching values; all fields with |
441 | | restricted ranges must have values within those ranges. */ |
442 | 3.35M | fixed_ok = true; |
443 | 3.60M | for (fix = 0; fix < opc->num_fixed_fields; fix++) |
444 | 3.44M | { |
445 | 3.44M | unsigned int field_bits; |
446 | 3.44M | const tic6x_insn_field *const field |
447 | 3.44M | = tic6x_field_from_fmt (fmt, opc->fixed_fields[fix].field_id); |
448 | | |
449 | 3.44M | if (!field) |
450 | 0 | { |
451 | 0 | printf ("opcode %x: missing field #%d for FIX #%d\n", |
452 | 0 | opcode, opc->fixed_fields[fix].field_id, fix); |
453 | 0 | abort (); |
454 | 0 | } |
455 | | |
456 | 3.44M | field_bits = tic6x_field_bits (opcode, field); |
457 | 3.44M | if (field_bits < opc->fixed_fields[fix].min_val |
458 | 1.21M | || field_bits > opc->fixed_fields[fix].max_val) |
459 | 3.19M | { |
460 | 3.19M | fixed_ok = false; |
461 | 3.19M | break; |
462 | 3.19M | } |
463 | 3.44M | } |
464 | 3.35M | if (!fixed_ok) |
465 | 3.19M | continue; |
466 | | |
467 | | /* The instruction matches. */ |
468 | | |
469 | | /* The p-bit indicates whether this instruction is in parallel |
470 | | with the *next* instruction, whereas the parallel bars |
471 | | indicate the instruction is in parallel with the *previous* |
472 | | instruction. Thus, we must find the p-bit for the previous |
473 | | instruction. */ |
474 | 162k | if (num_bits == 16 && (fp_offset & 0x2) == 2) |
475 | 8.70k | { |
476 | | /* This is the logically second (most significant; second in |
477 | | fp_offset terms because fp_offset relates to logical not |
478 | | physical addresses) instruction of a compact pair; find |
479 | | the p-bit for the first (least significant). */ |
480 | 8.70k | p_bit = header.p_bits[(fp_offset >> 2) << 1]; |
481 | 8.70k | } |
482 | 153k | else if (fp_offset >= 4) |
483 | 132k | { |
484 | | /* Find the last instruction of the previous word in this |
485 | | fetch packet. For compact instructions, this is the most |
486 | | significant 16 bits. */ |
487 | 132k | if (fetch_packet_header_based |
488 | 9.28k | && header.word_compact[(fp_offset >> 2) - 1]) |
489 | 5.56k | p_bit = header.p_bits[(fp_offset >> 1) - 1]; |
490 | 127k | else |
491 | 127k | { |
492 | 127k | unsigned int prev_opcode |
493 | 127k | = tic6x_extract_32 (fp + (fp_offset & 0x1c) - 4, info); |
494 | 127k | p_bit = (prev_opcode & 0x1) != 0; |
495 | 127k | } |
496 | 132k | } |
497 | 21.2k | else |
498 | 21.2k | { |
499 | | /* Find the last instruction of the previous fetch |
500 | | packet. */ |
501 | 21.2k | unsigned char fp_prev[32]; |
502 | | |
503 | 21.2k | status = info->read_memory_func (fp_addr - 32, fp_prev, 32, info); |
504 | 21.2k | if (status) |
505 | | /* No previous instruction to be parallel with. */ |
506 | 678 | p_bit = false; |
507 | 20.5k | else |
508 | 20.5k | { |
509 | 20.5k | bool prev_header_based; |
510 | 20.5k | tic6x_fetch_packet_header prev_header; |
511 | | |
512 | 20.5k | prev_header_based |
513 | 20.5k | = tic6x_check_fetch_packet_header (fp_prev, &prev_header, info); |
514 | 20.5k | if (prev_header_based) |
515 | 1.37k | { |
516 | 1.37k | if (prev_header.word_compact[6]) |
517 | 970 | p_bit = prev_header.p_bits[13]; |
518 | 402 | else |
519 | 402 | { |
520 | 402 | unsigned int prev_opcode = tic6x_extract_32 (fp_prev + 24, |
521 | 402 | info); |
522 | 402 | p_bit = (prev_opcode & 0x1) != 0; |
523 | 402 | } |
524 | 1.37k | } |
525 | 19.2k | else |
526 | 19.2k | { |
527 | 19.2k | unsigned int prev_opcode = tic6x_extract_32 (fp_prev + 28, |
528 | 19.2k | info); |
529 | 19.2k | p_bit = (prev_opcode & 0x1) != 0; |
530 | 19.2k | } |
531 | 20.5k | } |
532 | 21.2k | } |
533 | 162k | parallel = p_bit ? "|| " : ""; |
534 | | |
535 | 162k | if (opc->func_unit == tic6x_func_unit_nfu) |
536 | 16.5k | func_unit = ""; |
537 | 146k | else |
538 | 146k | { |
539 | 146k | unsigned int fld_num; |
540 | 146k | char func_unit_char; |
541 | 146k | const char *data_str; |
542 | 146k | bool have_areg = false; |
543 | 146k | bool have_cross = false; |
544 | | |
545 | 146k | func_unit_side = (opc->flags & TIC6X_FLAG_SIDE_B_ONLY) ? 2 : 0; |
546 | 146k | func_unit_cross = 0; |
547 | 146k | func_unit_data_side = (opc->flags & TIC6X_FLAG_SIDE_T2_ONLY) ? 2 : 0; |
548 | | |
549 | 822k | for (fld_num = 0; fld_num < opc->num_variable_fields; fld_num++) |
550 | 676k | { |
551 | 676k | const tic6x_coding_field *const enc = &opc->variable_fields[fld_num]; |
552 | 676k | const tic6x_insn_field *field; |
553 | 676k | unsigned int fld_val; |
554 | | |
555 | 676k | field = tic6x_field_from_fmt (fmt, enc->field_id); |
556 | | |
557 | 676k | if (!field) |
558 | 0 | { |
559 | 0 | printf ("opcode %x: could not retrieve field (field_id:%d)\n", |
560 | 0 | opcode, fld_num); |
561 | 0 | abort (); |
562 | 0 | } |
563 | | |
564 | 676k | fld_val = tic6x_field_bits (opcode, field); |
565 | | |
566 | 676k | switch (enc->coding_method) |
567 | 676k | { |
568 | 120k | case tic6x_coding_fu: |
569 | | /* The side must be specified exactly once. */ |
570 | 120k | if (func_unit_side) |
571 | 0 | { |
572 | 0 | printf ("opcode %x: field #%d use tic6x_coding_fu, but func_unit_side is already set!\n", |
573 | 0 | opcode, fld_num); |
574 | 0 | abort (); |
575 | 0 | } |
576 | 120k | func_unit_side = (fld_val ? 2 : 1); |
577 | 120k | break; |
578 | | |
579 | 52.2k | case tic6x_coding_data_fu: |
580 | | /* The data side must be specified exactly once. */ |
581 | 52.2k | if (func_unit_data_side) |
582 | 0 | { |
583 | 0 | printf ("opcode %x: field #%d use tic6x_coding_fu, but func_unit_side is already set!\n", |
584 | 0 | opcode, fld_num); |
585 | 0 | abort (); |
586 | 0 | } |
587 | 52.2k | func_unit_data_side = (fld_val ? 2 : 1); |
588 | 52.2k | break; |
589 | | |
590 | 57.8k | case tic6x_coding_xpath: |
591 | | /* Cross path use must be specified exactly |
592 | | once. */ |
593 | 57.8k | if (have_cross) |
594 | 0 | { |
595 | 0 | printf ("opcode %x: field #%d use tic6x_coding_xpath, have_cross is already set!\n", |
596 | 0 | opcode, fld_num); |
597 | 0 | abort (); |
598 | 0 | } |
599 | 57.8k | have_cross = true; |
600 | 57.8k | func_unit_cross = fld_val; |
601 | 57.8k | break; |
602 | | |
603 | 2.84k | case tic6x_coding_rside: |
604 | | /* If the format has a t field, use it for src/dst register side. */ |
605 | 2.84k | have_t = true; |
606 | 2.84k | t_val = fld_val; |
607 | 2.84k | func_unit_data_side = (t_val ? 2 : 1); |
608 | 2.84k | break; |
609 | | |
610 | 24.9k | case tic6x_coding_areg: |
611 | 24.9k | have_areg = true; |
612 | 24.9k | break; |
613 | | |
614 | 418k | default: |
615 | | /* Don't relate to functional units. */ |
616 | 418k | break; |
617 | 676k | } |
618 | 676k | } |
619 | | |
620 | | /* The side of the functional unit used must now have been |
621 | | determined either from the flags or from an instruction |
622 | | field. */ |
623 | 146k | if (func_unit_side != 1 && func_unit_side != 2) |
624 | 0 | { |
625 | 0 | printf ("opcode %x: func_unit_side is not encoded!\n", opcode); |
626 | 0 | abort (); |
627 | 0 | } |
628 | | |
629 | | /* Cross paths are not applicable when sides are specified |
630 | | for both address and data paths. */ |
631 | 146k | if (func_unit_data_side && have_cross) |
632 | 0 | { |
633 | 0 | printf ("opcode %x: xpath not applicable when side are specified both for address and data!\n", |
634 | 0 | opcode); |
635 | 0 | abort (); |
636 | 0 | } |
637 | | |
638 | | /* Separate address and data paths are only applicable for |
639 | | the D unit. */ |
640 | 146k | if (func_unit_data_side && opc->func_unit != tic6x_func_unit_d) |
641 | 0 | { |
642 | 0 | printf ("opcode %x: separate address and data paths only applicable for D unit!\n", |
643 | 0 | opcode); |
644 | 0 | abort (); |
645 | 0 | } |
646 | | |
647 | | /* If an address register is being used but in ADDA rather |
648 | | than a load or store, it uses a cross path for side-A |
649 | | instructions, and the cross path use is not specified by |
650 | | an instruction field. */ |
651 | 146k | if (have_areg && !func_unit_data_side) |
652 | 404 | { |
653 | 404 | if (have_cross) |
654 | 0 | { |
655 | 0 | printf ("opcode %x: illegal cross path specifier in adda opcode!\n", opcode); |
656 | 0 | abort (); |
657 | 0 | } |
658 | 404 | func_unit_cross = func_unit_side == 1; |
659 | 404 | } |
660 | | |
661 | 146k | switch (opc->func_unit) |
662 | 146k | { |
663 | 58.0k | case tic6x_func_unit_d: |
664 | 58.0k | func_unit_char = 'D'; |
665 | 58.0k | break; |
666 | | |
667 | 12.8k | case tic6x_func_unit_l: |
668 | 12.8k | func_unit_char = 'L'; |
669 | 12.8k | break; |
670 | | |
671 | 36.8k | case tic6x_func_unit_m: |
672 | 36.8k | func_unit_char = 'M'; |
673 | 36.8k | break; |
674 | | |
675 | 38.2k | case tic6x_func_unit_s: |
676 | 38.2k | func_unit_char = 'S'; |
677 | 38.2k | break; |
678 | | |
679 | 0 | default: |
680 | 0 | printf ("opcode %x: illegal func_unit specifier %d\n", opcode, opc->func_unit); |
681 | 0 | abort (); |
682 | 146k | } |
683 | | |
684 | 146k | switch (func_unit_data_side) |
685 | 146k | { |
686 | 90.9k | case 0: |
687 | 90.9k | data_str = ""; |
688 | 90.9k | break; |
689 | | |
690 | 27.4k | case 1: |
691 | 27.4k | data_str = "T1"; |
692 | 27.4k | break; |
693 | | |
694 | 27.5k | case 2: |
695 | 27.5k | data_str = "T2"; |
696 | 27.5k | break; |
697 | | |
698 | 0 | default: |
699 | 0 | printf ("opcode %x: illegal data func_unit specifier %d\n", |
700 | 0 | opcode, func_unit_data_side); |
701 | 0 | abort (); |
702 | 146k | } |
703 | | |
704 | 146k | if (opc->flags & TIC6X_FLAG_INSN16_BSIDE && func_unit_side == 1) |
705 | 149 | func_unit_cross = 1; |
706 | | |
707 | 146k | snprintf (func_unit_buf, sizeof func_unit_buf, " .%c%u%s%s", |
708 | 146k | func_unit_char, func_unit_side, |
709 | 146k | (func_unit_cross ? "X" : ""), data_str); |
710 | 146k | func_unit = func_unit_buf; |
711 | 146k | } |
712 | | |
713 | | /* For each operand there must be one or more fields set based |
714 | | on that operand, that can together be used to derive the |
715 | | operand value. */ |
716 | 162k | operands_ok = true; |
717 | 162k | num_operands = opc->num_operands; |
718 | 545k | for (op_num = 0; op_num < num_operands; op_num++) |
719 | 383k | { |
720 | 383k | unsigned int fld_num; |
721 | 383k | unsigned int mem_base_reg = 0; |
722 | 383k | bool mem_base_reg_known = false; |
723 | 383k | bool mem_base_reg_known_long = false; |
724 | 383k | unsigned int mem_offset = 0; |
725 | 383k | bool mem_offset_known = false; |
726 | 383k | bool mem_offset_known_long = false; |
727 | 383k | unsigned int mem_mode = 0; |
728 | 383k | bool mem_mode_known = false; |
729 | 383k | unsigned int mem_scaled = 0; |
730 | 383k | bool mem_scaled_known = false; |
731 | 383k | unsigned int crlo = 0; |
732 | 383k | bool crlo_known = false; |
733 | 383k | unsigned int crhi = 0; |
734 | 383k | bool crhi_known = false; |
735 | 383k | bool spmask_skip_operand = false; |
736 | 383k | unsigned int fcyc_bits = 0; |
737 | 383k | bool prev_sploop_found = false; |
738 | | |
739 | 383k | switch (opc->operand_info[op_num].form) |
740 | 383k | { |
741 | 187 | case tic6x_operand_b15reg: |
742 | | /* Fully determined by the functional unit. */ |
743 | 187 | operands_text[op_num] = true; |
744 | 187 | snprintf (operands[op_num], 24, "b15"); |
745 | 187 | continue; |
746 | | |
747 | 65 | case tic6x_operand_zreg: |
748 | | /* Fully determined by the functional unit. */ |
749 | 65 | operands_text[op_num] = true; |
750 | 65 | snprintf (operands[op_num], 24, "%c0", |
751 | 65 | (func_unit_side == 2 ? 'b' : 'a')); |
752 | 65 | continue; |
753 | | |
754 | 729 | case tic6x_operand_retreg: |
755 | | /* Fully determined by the functional unit. */ |
756 | 729 | operands_text[op_num] = true; |
757 | 729 | snprintf (operands[op_num], 24, "%c3", |
758 | 729 | (func_unit_side == 2 ? 'b' : 'a')); |
759 | 729 | continue; |
760 | | |
761 | 0 | case tic6x_operand_irp: |
762 | 0 | operands_text[op_num] = true; |
763 | 0 | snprintf (operands[op_num], 24, "irp"); |
764 | 0 | continue; |
765 | | |
766 | 0 | case tic6x_operand_nrp: |
767 | 0 | operands_text[op_num] = true; |
768 | 0 | snprintf (operands[op_num], 24, "nrp"); |
769 | 0 | continue; |
770 | | |
771 | 9 | case tic6x_operand_ilc: |
772 | 9 | operands_text[op_num] = true; |
773 | 9 | snprintf (operands[op_num], 24, "ilc"); |
774 | 9 | continue; |
775 | | |
776 | 4 | case tic6x_operand_hw_const_minus_1: |
777 | 4 | operands_text[op_num] = true; |
778 | 4 | snprintf (operands[op_num], 24, "-1"); |
779 | 4 | continue; |
780 | | |
781 | 9 | case tic6x_operand_hw_const_0: |
782 | 9 | operands_text[op_num] = true; |
783 | 9 | snprintf (operands[op_num], 24, "0"); |
784 | 9 | continue; |
785 | | |
786 | 12 | case tic6x_operand_hw_const_1: |
787 | 12 | operands_text[op_num] = true; |
788 | 12 | snprintf (operands[op_num], 24, "1"); |
789 | 12 | continue; |
790 | | |
791 | 5.90k | case tic6x_operand_hw_const_5: |
792 | 5.90k | operands_text[op_num] = true; |
793 | 5.90k | snprintf (operands[op_num], 24, "5"); |
794 | 5.90k | continue; |
795 | | |
796 | 2.95k | case tic6x_operand_hw_const_16: |
797 | 2.95k | operands_text[op_num] = true; |
798 | 2.95k | snprintf (operands[op_num], 24, "16"); |
799 | 2.95k | continue; |
800 | | |
801 | 30 | case tic6x_operand_hw_const_24: |
802 | 30 | operands_text[op_num] = true; |
803 | 30 | snprintf (operands[op_num], 24, "24"); |
804 | 30 | continue; |
805 | | |
806 | 65 | case tic6x_operand_hw_const_31: |
807 | 65 | operands_text[op_num] = true; |
808 | 65 | snprintf (operands[op_num], 24, "31"); |
809 | 65 | continue; |
810 | | |
811 | 373k | default: |
812 | 373k | break; |
813 | 383k | } |
814 | | |
815 | 1.42M | for (fld_num = 0; fld_num < opc->num_variable_fields; fld_num++) |
816 | 1.42M | { |
817 | 1.42M | const tic6x_coding_field *const enc |
818 | 1.42M | = &opc->variable_fields[fld_num]; |
819 | 1.42M | const tic6x_insn_field *field; |
820 | 1.42M | unsigned int fld_val; |
821 | 1.42M | unsigned int reg_base = 0; |
822 | 1.42M | signed int signed_fld_val; |
823 | 1.42M | char reg_side = '?'; |
824 | | |
825 | 1.42M | if (enc->operand_num != op_num) |
826 | 730k | continue; |
827 | 691k | field = tic6x_field_from_fmt (fmt, enc->field_id); |
828 | 691k | if (!field) |
829 | 0 | { |
830 | 0 | printf ("opcode %x: missing field (field_id:%d) in format\n", opcode, enc->field_id); |
831 | 0 | abort (); |
832 | 0 | } |
833 | 691k | fld_val = tic6x_field_bits (opcode, field); |
834 | 691k | switch (enc->coding_method) |
835 | 691k | { |
836 | 206 | case tic6x_coding_cst_s3i: |
837 | 206 | (fld_val == 0x00) && (fld_val = 0x10); |
838 | 206 | (fld_val == 0x07) && (fld_val = 0x08); |
839 | | /* Fall through. */ |
840 | 18.6k | case tic6x_coding_ucst: |
841 | 25.9k | case tic6x_coding_ulcst_dpr_byte: |
842 | 33.1k | case tic6x_coding_ulcst_dpr_half: |
843 | 43.6k | case tic6x_coding_ulcst_dpr_word: |
844 | 43.6k | case tic6x_coding_lcst_low16: |
845 | 43.6k | switch (opc->operand_info[op_num].form) |
846 | 43.6k | { |
847 | 18.3k | case tic6x_operand_asm_const: |
848 | 19.0k | case tic6x_operand_link_const: |
849 | 19.0k | operands_text[op_num] = true; |
850 | 19.0k | snprintf (operands[op_num], 24, "%u", fld_val); |
851 | 19.0k | break; |
852 | | |
853 | 24.5k | case tic6x_operand_mem_long: |
854 | 24.5k | mem_offset = fld_val; |
855 | 24.5k | mem_offset_known_long = true; |
856 | 24.5k | break; |
857 | | |
858 | 0 | default: |
859 | 0 | printf ("opcode %x: illegal operand form for operand#%d\n", opcode, op_num); |
860 | 0 | abort (); |
861 | 43.6k | } |
862 | 43.6k | break; |
863 | | |
864 | 43.6k | case tic6x_coding_lcst_high16: |
865 | 2.99k | operands_text[op_num] = true; |
866 | 2.99k | snprintf (operands[op_num], 24, "%u", fld_val << 16); |
867 | 2.99k | break; |
868 | | |
869 | 762 | case tic6x_coding_scst_l3i: |
870 | 762 | operands_text[op_num] = true; |
871 | 762 | if (fld_val == 0) |
872 | 112 | { |
873 | 112 | signed_fld_val = 8; |
874 | 112 | } |
875 | 650 | else |
876 | 650 | { |
877 | 650 | signed_fld_val = (signed int) fld_val; |
878 | 650 | signed_fld_val ^= (1 << (tic6x_field_width (field) - 1)); |
879 | 650 | signed_fld_val -= (1 << (tic6x_field_width (field) - 1)); |
880 | 650 | } |
881 | 762 | snprintf (operands[op_num], 24, "%d", signed_fld_val); |
882 | 762 | break; |
883 | | |
884 | 13.0k | case tic6x_coding_scst: |
885 | 13.0k | operands_text[op_num] = true; |
886 | 13.0k | signed_fld_val = (signed int) fld_val; |
887 | 13.0k | signed_fld_val ^= (1 << (tic6x_field_width (field) - 1)); |
888 | 13.0k | signed_fld_val -= (1 << (tic6x_field_width (field) - 1)); |
889 | 13.0k | snprintf (operands[op_num], 24, "%d", signed_fld_val); |
890 | 13.0k | break; |
891 | | |
892 | 15.2k | case tic6x_coding_ucst_minus_one: |
893 | 15.2k | operands_text[op_num] = true; |
894 | 15.2k | snprintf (operands[op_num], 24, "%u", fld_val + 1); |
895 | 15.2k | break; |
896 | | |
897 | 5.63k | case tic6x_coding_pcrel: |
898 | 6.06k | case tic6x_coding_pcrel_half: |
899 | 6.06k | signed_fld_val = (signed int) fld_val; |
900 | 6.06k | signed_fld_val ^= (1 << (tic6x_field_width (field) - 1)); |
901 | 6.06k | signed_fld_val -= (1 << (tic6x_field_width (field) - 1)); |
902 | 6.06k | if (fetch_packet_header_based |
903 | 548 | && enc->coding_method == tic6x_coding_pcrel_half) |
904 | 409 | signed_fld_val *= 2; |
905 | 5.65k | else |
906 | 5.65k | signed_fld_val *= 4; |
907 | 6.06k | operands_pcrel[op_num] = true; |
908 | 6.06k | operands_addresses[op_num] = fp_addr + signed_fld_val; |
909 | 6.06k | break; |
910 | | |
911 | 215 | case tic6x_coding_regpair_msb: |
912 | 215 | if (opc->operand_info[op_num].form != tic6x_operand_regpair) |
913 | 0 | abort (); |
914 | 215 | operands_text[op_num] = true; |
915 | 215 | snprintf (operands[op_num], 24, "%c%u:%c%u", |
916 | 215 | (func_unit_side == 2 ? 'b' : 'a'), (fld_val | 0x1), |
917 | 215 | (func_unit_side == 2 ? 'b' : 'a'), (fld_val | 0x1) - 1); |
918 | 215 | break; |
919 | | |
920 | 5.90k | case tic6x_coding_pcrel_half_unsigned: |
921 | 5.90k | operands_pcrel[op_num] = true; |
922 | 5.90k | operands_addresses[op_num] = fp_addr + 2 * fld_val; |
923 | 5.90k | break; |
924 | | |
925 | 4.75k | case tic6x_coding_reg_shift: |
926 | 4.75k | fld_val <<= 1; |
927 | | /* Fall through. */ |
928 | 279k | case tic6x_coding_reg: |
929 | 279k | if (num_bits == 16 && header.rs && !(opc->flags & TIC6X_FLAG_INSN16_NORS)) |
930 | 10.5k | { |
931 | 10.5k | reg_base = 16; |
932 | 10.5k | } |
933 | 279k | switch (opc->operand_info[op_num].form) |
934 | 279k | { |
935 | 2.11k | case tic6x_operand_treg: |
936 | 2.11k | if (!have_t) |
937 | 0 | { |
938 | 0 | printf ("opcode %x: operand treg but missing t field\n", opcode); |
939 | 0 | abort (); |
940 | 0 | } |
941 | 2.11k | operands_text[op_num] = true; |
942 | 2.11k | reg_side = t_val ? 'b' : 'a'; |
943 | 2.11k | snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); |
944 | 2.11k | break; |
945 | | |
946 | 112k | case tic6x_operand_reg: |
947 | 112k | operands_text[op_num] = true; |
948 | 112k | reg_side = (func_unit_side == 2) ? 'b' : 'a'; |
949 | 112k | snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); |
950 | 112k | break; |
951 | | |
952 | 306 | case tic6x_operand_reg_nors: |
953 | 306 | operands_text[op_num] = true; |
954 | 306 | reg_side = (func_unit_side == 2) ? 'b' : 'a'; |
955 | 306 | snprintf (operands[op_num], 24, "%c%u", reg_side, fld_val); |
956 | 306 | break; |
957 | | |
958 | 9 | case tic6x_operand_reg_bside: |
959 | 9 | operands_text[op_num] = true; |
960 | 9 | snprintf (operands[op_num], 24, "b%u", reg_base + fld_val); |
961 | 9 | break; |
962 | | |
963 | 254 | case tic6x_operand_reg_bside_nors: |
964 | 254 | operands_text[op_num] = true; |
965 | 254 | snprintf (operands[op_num], 24, "b%u", fld_val); |
966 | 254 | break; |
967 | | |
968 | 55.9k | case tic6x_operand_xreg: |
969 | 55.9k | operands_text[op_num] = true; |
970 | 55.9k | reg_side = ((func_unit_side == 2) ^ func_unit_cross) ? 'b' : 'a'; |
971 | 55.9k | snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); |
972 | 55.9k | break; |
973 | | |
974 | 45.9k | case tic6x_operand_dreg: |
975 | 45.9k | operands_text[op_num] = true; |
976 | 45.9k | reg_side = (func_unit_data_side == 2) ? 'b' : 'a'; |
977 | 45.9k | snprintf (operands[op_num], 24, "%c%u", reg_side, reg_base + fld_val); |
978 | 45.9k | break; |
979 | | |
980 | 25.5k | case tic6x_operand_regpair: |
981 | 25.5k | operands_text[op_num] = true; |
982 | 25.5k | if (fld_val & 1) |
983 | 4.59k | operands_ok = false; |
984 | 25.5k | reg_side = (func_unit_side == 2) ? 'b' : 'a'; |
985 | 25.5k | snprintf (operands[op_num], 24, "%c%u:%c%u", |
986 | 25.5k | reg_side, reg_base + fld_val + 1, |
987 | 25.5k | reg_side, reg_base + fld_val); |
988 | 25.5k | break; |
989 | | |
990 | 1.87k | case tic6x_operand_xregpair: |
991 | 1.87k | operands_text[op_num] = true; |
992 | 1.87k | if (fld_val & 1) |
993 | 842 | operands_ok = false; |
994 | 1.87k | reg_side = ((func_unit_side == 2) ^ func_unit_cross) ? 'b' : 'a'; |
995 | 1.87k | snprintf (operands[op_num], 24, "%c%u:%c%u", |
996 | 1.87k | reg_side, reg_base + fld_val + 1, |
997 | 1.87k | reg_side, reg_base + fld_val); |
998 | 1.87k | break; |
999 | | |
1000 | 730 | case tic6x_operand_tregpair: |
1001 | 730 | if (!have_t) |
1002 | 0 | { |
1003 | 0 | printf ("opcode %x: operand tregpair but missing t field\n", opcode); |
1004 | 0 | abort (); |
1005 | 0 | } |
1006 | 730 | operands_text[op_num] = true; |
1007 | 730 | if (fld_val & 1) |
1008 | 4 | operands_ok = false; |
1009 | 730 | reg_side = t_val ? 'b' : 'a'; |
1010 | 730 | snprintf (operands[op_num], 24, "%c%u:%c%u", |
1011 | 730 | reg_side, reg_base + fld_val + 1, |
1012 | 730 | reg_side, reg_base + fld_val); |
1013 | 730 | break; |
1014 | | |
1015 | 6.27k | case tic6x_operand_dregpair: |
1016 | 6.27k | operands_text[op_num] = true; |
1017 | 6.27k | if (fld_val & 1) |
1018 | 1.00k | operands_ok = false; |
1019 | 6.27k | reg_side = (func_unit_data_side) == 2 ? 'b' : 'a'; |
1020 | 6.27k | snprintf (operands[op_num], 24, "%c%u:%c%u", |
1021 | 6.27k | reg_side, reg_base + fld_val + 1, |
1022 | 6.27k | reg_side, reg_base + fld_val); |
1023 | 6.27k | break; |
1024 | | |
1025 | 4 | case tic6x_operand_mem_deref: |
1026 | 4 | operands_text[op_num] = true; |
1027 | 4 | reg_side = func_unit_side == 2 ? 'b' : 'a'; |
1028 | 4 | snprintf (operands[op_num], 24, "*%c%u", reg_side, reg_base + fld_val); |
1029 | 4 | break; |
1030 | | |
1031 | 24.7k | case tic6x_operand_mem_short: |
1032 | 27.6k | case tic6x_operand_mem_ndw: |
1033 | 27.6k | mem_base_reg = fld_val; |
1034 | 27.6k | mem_base_reg_known = true; |
1035 | 27.6k | break; |
1036 | | |
1037 | 0 | default: |
1038 | 0 | printf ("opcode %x: unexpected operand form %d for operand #%d", |
1039 | 0 | opcode, opc->operand_info[op_num].form, op_num); |
1040 | 0 | abort (); |
1041 | 279k | } |
1042 | 279k | break; |
1043 | | |
1044 | 279k | case tic6x_coding_reg_ptr: |
1045 | 2.40k | switch (opc->operand_info[op_num].form) |
1046 | 2.40k | { |
1047 | 2.22k | case tic6x_operand_mem_short: |
1048 | 2.40k | case tic6x_operand_mem_ndw: |
1049 | 2.40k | if (fld_val > 0x3u) |
1050 | 0 | { |
1051 | 0 | printf("opcode %x: illegal field value for ptr register of operand #%d (%d)", |
1052 | 0 | opcode, op_num, fld_val); |
1053 | 0 | abort (); |
1054 | 0 | } |
1055 | 2.40k | mem_base_reg = 0x4 | fld_val; |
1056 | 2.40k | mem_base_reg_known = true; |
1057 | 2.40k | break; |
1058 | | |
1059 | 0 | default: |
1060 | 0 | printf ("opcode %x: unexpected operand form %d for operand #%d", |
1061 | 0 | opcode, opc->operand_info[op_num].form, op_num); |
1062 | 0 | abort (); |
1063 | 2.40k | } |
1064 | 2.40k | break; |
1065 | | |
1066 | 24.9k | case tic6x_coding_areg: |
1067 | 24.9k | switch (opc->operand_info[op_num].form) |
1068 | 24.9k | { |
1069 | 404 | case tic6x_operand_areg: |
1070 | 404 | operands_text[op_num] = true; |
1071 | 404 | snprintf (operands[op_num], 24, "b%u", |
1072 | 404 | fld_val ? 15u : 14u); |
1073 | 404 | break; |
1074 | | |
1075 | 24.5k | case tic6x_operand_mem_long: |
1076 | 24.5k | mem_base_reg = fld_val ? 15u : 14u; |
1077 | 24.5k | mem_base_reg_known_long = true; |
1078 | 24.5k | break; |
1079 | | |
1080 | 0 | default: |
1081 | 0 | printf ("opcode %x: bad operand form\n", opcode); |
1082 | 0 | abort (); |
1083 | 24.9k | } |
1084 | 24.9k | break; |
1085 | | |
1086 | 24.9k | case tic6x_coding_mem_offset_minus_one_noscale: |
1087 | 498 | case tic6x_coding_mem_offset_minus_one: |
1088 | 498 | fld_val += 1; |
1089 | | /* Fall through. */ |
1090 | 3.61k | case tic6x_coding_mem_offset_noscale: |
1091 | 30.5k | case tic6x_coding_mem_offset: |
1092 | 30.5k | mem_offset = fld_val; |
1093 | 30.5k | mem_offset_known = true; |
1094 | 30.5k | if (num_bits == 16) |
1095 | 2.84k | { |
1096 | 2.84k | mem_mode_known = true; |
1097 | 2.84k | mem_mode = TIC6X_INSN16_MEM_MODE_VAL (opc->flags); |
1098 | 2.84k | mem_scaled_known = true; |
1099 | 2.84k | mem_scaled = true; |
1100 | 2.84k | if (opc->flags & TIC6X_FLAG_INSN16_B15PTR) |
1101 | 441 | { |
1102 | 441 | mem_base_reg_known = true; |
1103 | 441 | mem_base_reg = 15; |
1104 | 441 | } |
1105 | 2.84k | if ( enc->coding_method == tic6x_coding_mem_offset_noscale |
1106 | 2.69k | || enc->coding_method == tic6x_coding_mem_offset_noscale ) |
1107 | 145 | mem_scaled = false; |
1108 | 2.84k | } |
1109 | 30.5k | break; |
1110 | | |
1111 | 27.6k | case tic6x_coding_mem_mode: |
1112 | 27.6k | mem_mode = fld_val; |
1113 | 27.6k | mem_mode_known = true; |
1114 | 27.6k | break; |
1115 | | |
1116 | 2.97k | case tic6x_coding_scaled: |
1117 | 2.97k | mem_scaled = fld_val; |
1118 | 2.97k | mem_scaled_known = true; |
1119 | 2.97k | break; |
1120 | | |
1121 | 1.19k | case tic6x_coding_crlo: |
1122 | 1.19k | crlo = fld_val; |
1123 | 1.19k | crlo_known = true; |
1124 | 1.19k | break; |
1125 | | |
1126 | 1.19k | case tic6x_coding_crhi: |
1127 | 1.19k | crhi = fld_val; |
1128 | 1.19k | crhi_known = true; |
1129 | 1.19k | break; |
1130 | | |
1131 | 96 | case tic6x_coding_fstg: |
1132 | 192 | case tic6x_coding_fcyc: |
1133 | 192 | if (!prev_sploop_found) |
1134 | 192 | { |
1135 | 192 | bfd_vma search_fp_addr = fp_addr; |
1136 | 192 | bfd_vma search_fp_offset = fp_offset; |
1137 | 192 | bool search_fp_header_based |
1138 | 192 | = fetch_packet_header_based; |
1139 | 192 | tic6x_fetch_packet_header search_fp_header = header; |
1140 | 192 | unsigned char search_fp[32]; |
1141 | 192 | unsigned int search_num_bits; |
1142 | 192 | unsigned int search_opcode; |
1143 | 192 | unsigned int sploop_ii = 0; |
1144 | 192 | int i; |
1145 | | |
1146 | 192 | memcpy (search_fp, fp, 32); |
1147 | | |
1148 | | /* To interpret these bits in an SPKERNEL |
1149 | | instruction, we must find the previous |
1150 | | SPLOOP-family instruction. It may come up to |
1151 | | 48 execute packets earlier. */ |
1152 | 47.6k | for (i = 0; i < 48 * 8; i++) |
1153 | 47.6k | { |
1154 | | /* Find the previous instruction. */ |
1155 | 47.6k | if (search_fp_offset & 2) |
1156 | 930 | search_fp_offset -= 2; |
1157 | 46.7k | else if (search_fp_offset >= 4) |
1158 | 40.7k | { |
1159 | 40.7k | if (search_fp_header_based |
1160 | 1.37k | && (search_fp_header.word_compact |
1161 | 1.37k | [(search_fp_offset >> 2) - 1])) |
1162 | 744 | search_fp_offset -= 2; |
1163 | 40.0k | else |
1164 | 40.0k | search_fp_offset -= 4; |
1165 | 40.7k | } |
1166 | 5.97k | else |
1167 | 5.97k | { |
1168 | 5.97k | search_fp_addr -= 32; |
1169 | 5.97k | status = info->read_memory_func (search_fp_addr, |
1170 | 5.97k | search_fp, |
1171 | 5.97k | 32, info); |
1172 | 5.97k | if (status) |
1173 | | /* No previous SPLOOP instruction. */ |
1174 | 162 | break; |
1175 | 5.81k | search_fp_header_based |
1176 | 5.81k | = (tic6x_check_fetch_packet_header |
1177 | 5.81k | (search_fp, &search_fp_header, info)); |
1178 | 5.81k | if (search_fp_header_based) |
1179 | 180 | search_fp_offset |
1180 | 180 | = search_fp_header.word_compact[6] ? 26 : 24; |
1181 | 5.63k | else |
1182 | 5.63k | search_fp_offset = 28; |
1183 | 5.81k | } |
1184 | | |
1185 | | /* Extract the previous instruction. */ |
1186 | 47.4k | if (search_fp_header_based) |
1187 | 2.48k | search_num_bits |
1188 | 2.48k | = (search_fp_header.word_compact[search_fp_offset |
1189 | 2.48k | >> 2] |
1190 | 2.48k | ? 16 |
1191 | 2.48k | : 32); |
1192 | 45.0k | else |
1193 | 45.0k | search_num_bits = 32; |
1194 | 47.4k | if (search_num_bits == 16) |
1195 | 1.78k | { |
1196 | 1.78k | if (info->endian == BFD_ENDIAN_LITTLE) |
1197 | 0 | search_opcode |
1198 | 0 | = (tic6x_extract_16 |
1199 | 0 | (search_fp + search_fp_offset, &header, info)); |
1200 | 1.78k | else |
1201 | 1.78k | search_opcode |
1202 | 1.78k | = (tic6x_extract_16 |
1203 | 1.78k | (search_fp + (search_fp_offset ^ 2), &header, |
1204 | 1.78k | info)); |
1205 | 1.78k | } |
1206 | 45.7k | else |
1207 | 45.7k | search_opcode |
1208 | 45.7k | = tic6x_extract_32 (search_fp + search_fp_offset, |
1209 | 45.7k | info); |
1210 | | |
1211 | | /* Check whether it is an SPLOOP-family |
1212 | | instruction. */ |
1213 | 47.4k | if (search_num_bits == 32 |
1214 | 45.7k | && ((search_opcode & 0x003ffffe) == 0x00038000 |
1215 | 45.7k | || (search_opcode & 0x003ffffe) == 0x0003a000 |
1216 | 45.7k | || ((search_opcode & 0x003ffffe) |
1217 | 45.7k | == 0x0003e000))) |
1218 | 0 | { |
1219 | 0 | prev_sploop_found = true; |
1220 | 0 | sploop_ii = ((search_opcode >> 23) & 0x1f) + 1; |
1221 | 0 | } |
1222 | 47.4k | else if (search_num_bits == 16 |
1223 | 1.78k | && (search_opcode & 0x3c7e) == 0x0c66) |
1224 | 2 | { |
1225 | 2 | prev_sploop_found = true; |
1226 | 2 | sploop_ii |
1227 | 2 | = (((search_opcode >> 7) & 0x7) |
1228 | 2 | | ((search_opcode >> 11) & 0x8)) + 1; |
1229 | 2 | } |
1230 | 47.4k | if (prev_sploop_found) |
1231 | 2 | { |
1232 | 2 | if (sploop_ii <= 0) |
1233 | 0 | { |
1234 | 0 | printf ("opcode %x: sloop index not found (%d)\n", opcode, sploop_ii); |
1235 | 0 | abort (); |
1236 | 0 | } |
1237 | 2 | else if (sploop_ii <= 1) |
1238 | 0 | fcyc_bits = 0; |
1239 | 2 | else if (sploop_ii <= 2) |
1240 | 0 | fcyc_bits = 1; |
1241 | 2 | else if (sploop_ii <= 4) |
1242 | 0 | fcyc_bits = 2; |
1243 | 2 | else if (sploop_ii <= 8) |
1244 | 0 | fcyc_bits = 3; |
1245 | 2 | else if (sploop_ii <= 14) |
1246 | 2 | fcyc_bits = 4; |
1247 | 0 | else |
1248 | 0 | prev_sploop_found = false; |
1249 | 2 | } |
1250 | 47.4k | if (prev_sploop_found) |
1251 | 2 | break; |
1252 | 47.4k | } |
1253 | 192 | } |
1254 | 192 | if (!prev_sploop_found) |
1255 | 190 | { |
1256 | 190 | operands_ok = false; |
1257 | 190 | operands_text[op_num] = true; |
1258 | 190 | break; |
1259 | 190 | } |
1260 | 2 | if (fcyc_bits > tic6x_field_width(field)) |
1261 | 0 | { |
1262 | 0 | printf ("opcode %x: illegal fcyc value (%d)\n", opcode, fcyc_bits); |
1263 | 0 | abort (); |
1264 | 0 | } |
1265 | 2 | if (enc->coding_method == tic6x_coding_fstg) |
1266 | 1 | { |
1267 | 1 | int i, t; |
1268 | 3 | for (t = 0, i = fcyc_bits; i < 6; i++) |
1269 | 2 | t = (t << 1) | ((fld_val >> i) & 1); |
1270 | 1 | operands_text[op_num] = true; |
1271 | 1 | snprintf (operands[op_num], 24, "%u", t); |
1272 | 1 | } |
1273 | 1 | else |
1274 | 1 | { |
1275 | 1 | operands_text[op_num] = true; |
1276 | 1 | snprintf (operands[op_num], 24, "%u", |
1277 | 1 | fld_val & ((1 << fcyc_bits) - 1)); |
1278 | 1 | } |
1279 | 2 | break; |
1280 | | |
1281 | 1.00k | case tic6x_coding_spmask: |
1282 | 1.00k | if (fld_val == 0) |
1283 | 64 | spmask_skip_operand = true; |
1284 | 943 | else |
1285 | 943 | { |
1286 | 943 | char *p; |
1287 | 943 | unsigned int i; |
1288 | | |
1289 | 943 | operands_text[op_num] = true; |
1290 | 943 | p = operands[op_num]; |
1291 | 8.48k | for (i = 0; i < 8; i++) |
1292 | 7.54k | if (fld_val & (1 << i)) |
1293 | 2.93k | { |
1294 | 2.93k | *p++ = "LSDM"[i/2]; |
1295 | 2.93k | *p++ = '1' + (i & 1); |
1296 | 2.93k | *p++ = ','; |
1297 | 2.93k | } |
1298 | 943 | p[-1] = 0; |
1299 | 943 | } |
1300 | 1.00k | break; |
1301 | | |
1302 | 119k | case tic6x_coding_fu: |
1303 | 172k | case tic6x_coding_data_fu: |
1304 | 229k | case tic6x_coding_xpath: |
1305 | 232k | case tic6x_coding_rside: |
1306 | | /* Don't relate to operands, so operand number is |
1307 | | meaningless. */ |
1308 | 232k | break; |
1309 | | |
1310 | 0 | default: |
1311 | 0 | printf ("opcode %x: illegal field encoding (%d)\n", opcode, enc->coding_method); |
1312 | 0 | abort (); |
1313 | 691k | } |
1314 | | |
1315 | 691k | if (mem_base_reg_known_long && mem_offset_known_long) |
1316 | 24.5k | { |
1317 | 24.5k | if (operands_text[op_num] || operands_pcrel[op_num]) |
1318 | 0 | { |
1319 | 0 | printf ("opcode %x: long access but operands already known ?\n", opcode); |
1320 | 0 | abort (); |
1321 | 0 | } |
1322 | 24.5k | operands_text[op_num] = true; |
1323 | 24.5k | snprintf (operands[op_num], 24, "*+b%u(%u)", mem_base_reg, |
1324 | 24.5k | mem_offset * opc->operand_info[op_num].size); |
1325 | 24.5k | } |
1326 | | |
1327 | 691k | if (mem_base_reg_known && mem_offset_known && mem_mode_known |
1328 | 33.5k | && (mem_scaled_known |
1329 | 27.6k | || (opc->operand_info[op_num].form |
1330 | 27.6k | != tic6x_operand_mem_ndw))) |
1331 | 30.5k | { |
1332 | 30.5k | char side; |
1333 | 30.5k | char base[4]; |
1334 | 30.5k | bool offset_is_reg; |
1335 | 30.5k | bool offset_scaled; |
1336 | 30.5k | char offset[4]; |
1337 | 30.5k | char offsetp[6]; |
1338 | | |
1339 | 30.5k | if (operands_text[op_num] || operands_pcrel[op_num]) |
1340 | 0 | { |
1341 | 0 | printf ("opcode %x: mem access operands already known ?\n", opcode); |
1342 | 0 | abort (); |
1343 | 0 | } |
1344 | | |
1345 | 30.5k | side = func_unit_side == 2 ? 'b' : 'a'; |
1346 | 30.5k | snprintf (base, 4, "%c%u", side, mem_base_reg); |
1347 | | |
1348 | 30.5k | offset_is_reg = (mem_mode & 4) != 0; |
1349 | 30.5k | if (offset_is_reg) |
1350 | 9.20k | { |
1351 | | |
1352 | 9.20k | if (num_bits == 16 && header.rs && !(opc->flags & TIC6X_FLAG_INSN16_NORS)) |
1353 | 483 | { |
1354 | 483 | reg_base = 16; |
1355 | 483 | } |
1356 | 9.20k | snprintf (offset, 4, "%c%u", side, reg_base + mem_offset); |
1357 | 9.20k | if (opc->operand_info[op_num].form |
1358 | 9.20k | == tic6x_operand_mem_ndw) |
1359 | 1.25k | offset_scaled = mem_scaled != 0; |
1360 | 7.94k | else |
1361 | 7.94k | offset_scaled = true; |
1362 | 9.20k | } |
1363 | 21.3k | else |
1364 | 21.3k | { |
1365 | 21.3k | if (opc->operand_info[op_num].form |
1366 | 21.3k | == tic6x_operand_mem_ndw) |
1367 | 1.89k | { |
1368 | 1.89k | offset_scaled = mem_scaled != 0; |
1369 | 1.89k | snprintf (offset, 4, "%u", mem_offset); |
1370 | 1.89k | } |
1371 | 19.4k | else |
1372 | 19.4k | { |
1373 | 19.4k | offset_scaled = false; |
1374 | 19.4k | snprintf (offset, 4, "%u", |
1375 | 19.4k | (mem_offset |
1376 | 19.4k | * opc->operand_info[op_num].size)); |
1377 | 19.4k | } |
1378 | 21.3k | } |
1379 | | |
1380 | 30.5k | if (offset_scaled) |
1381 | 8.63k | snprintf (offsetp, 6, "[%s]", offset); |
1382 | 21.9k | else |
1383 | 21.9k | snprintf (offsetp, 6, "(%s)", offset); |
1384 | | |
1385 | 30.5k | operands_text[op_num] = true; |
1386 | 30.5k | switch (mem_mode & ~4u) |
1387 | 30.5k | { |
1388 | 6.44k | case 0: |
1389 | 6.44k | snprintf (operands[op_num], 24, "*-%s%s", base, offsetp); |
1390 | 6.44k | break; |
1391 | | |
1392 | 4.96k | case 1: |
1393 | 4.96k | snprintf (operands[op_num], 24, "*+%s%s", base, offsetp); |
1394 | 4.96k | break; |
1395 | | |
1396 | 3.93k | case 2: |
1397 | 6.60k | case 3: |
1398 | 6.60k | operands_ok = false; |
1399 | 6.60k | break; |
1400 | | |
1401 | 3.23k | case 8: |
1402 | 3.23k | snprintf (operands[op_num], 24, "*--%s%s", base, |
1403 | 3.23k | offsetp); |
1404 | 3.23k | break; |
1405 | | |
1406 | 1.96k | case 9: |
1407 | 1.96k | snprintf (operands[op_num], 24, "*++%s%s", base, |
1408 | 1.96k | offsetp); |
1409 | 1.96k | break; |
1410 | | |
1411 | 3.16k | case 10: |
1412 | 3.16k | snprintf (operands[op_num], 24, "*%s--%s", base, |
1413 | 3.16k | offsetp); |
1414 | 3.16k | break; |
1415 | | |
1416 | 4.15k | case 11: |
1417 | 4.15k | snprintf (operands[op_num], 24, "*%s++%s", base, |
1418 | 4.15k | offsetp); |
1419 | 4.15k | break; |
1420 | | |
1421 | 0 | default: |
1422 | 0 | printf ("*** unknown mem_mode : %d \n", mem_mode); |
1423 | 0 | abort (); |
1424 | 30.5k | } |
1425 | 30.5k | } |
1426 | | |
1427 | 691k | if (crlo_known && crhi_known) |
1428 | 1.19k | { |
1429 | 1.19k | tic6x_rw rw; |
1430 | 1.19k | tic6x_ctrl_id crid; |
1431 | | |
1432 | 1.19k | if (operands_text[op_num] || operands_pcrel[op_num]) |
1433 | 0 | { |
1434 | 0 | printf ("*** abort crlo crli\n"); |
1435 | 0 | abort (); |
1436 | 0 | } |
1437 | | |
1438 | 1.19k | rw = opc->operand_info[op_num].rw; |
1439 | 1.19k | if (rw != tic6x_rw_read |
1440 | 1.03k | && rw != tic6x_rw_write) |
1441 | 0 | { |
1442 | 0 | printf ("*** abort rw : %d\n", rw); |
1443 | 0 | abort (); |
1444 | 0 | } |
1445 | | |
1446 | 33.8k | for (crid = 0; crid < tic6x_ctrl_max; crid++) |
1447 | 32.7k | { |
1448 | 32.7k | if (crlo == tic6x_ctrl_table[crid].crlo |
1449 | 1.19k | && (crhi & tic6x_ctrl_table[crid].crhi_mask) == 0 |
1450 | 123 | && (rw == tic6x_rw_read |
1451 | 123 | ? (tic6x_ctrl_table[crid].rw == tic6x_rw_read |
1452 | 81 | || (tic6x_ctrl_table[crid].rw |
1453 | 81 | == tic6x_rw_read_write)) |
1454 | 123 | : (tic6x_ctrl_table[crid].rw == tic6x_rw_write |
1455 | 35 | || (tic6x_ctrl_table[crid].rw |
1456 | 35 | == tic6x_rw_read_write)))) |
1457 | 115 | break; |
1458 | 32.7k | } |
1459 | 1.19k | if (crid == tic6x_ctrl_max) |
1460 | 1.08k | { |
1461 | 1.08k | operands_text[op_num] = true; |
1462 | 1.08k | operands_ok = false; |
1463 | 1.08k | } |
1464 | 115 | else |
1465 | 115 | { |
1466 | 115 | operands_text[op_num] = true; |
1467 | 115 | snprintf (operands[op_num], 24, "%s", |
1468 | 115 | tic6x_ctrl_table[crid].name); |
1469 | 115 | } |
1470 | 1.19k | } |
1471 | | |
1472 | 691k | if (operands_text[op_num] || operands_pcrel[op_num] |
1473 | 318k | || spmask_skip_operand) |
1474 | 373k | break; |
1475 | 691k | } |
1476 | | /* end for fld_num */ |
1477 | | |
1478 | 373k | if (spmask_skip_operand) |
1479 | 64 | { |
1480 | | /* SPMASK operands are only valid as the single operand |
1481 | | in the opcode table. */ |
1482 | 64 | if (num_operands != 1) |
1483 | 0 | { |
1484 | 0 | printf ("opcode: %x, num_operands != 1 : %d\n", opcode, num_operands); |
1485 | 0 | abort (); |
1486 | 0 | } |
1487 | 64 | num_operands = 0; |
1488 | 64 | break; |
1489 | 64 | } |
1490 | | |
1491 | | /* The operand must by now have been decoded. */ |
1492 | 373k | if (!operands_text[op_num] && !operands_pcrel[op_num]) |
1493 | 0 | { |
1494 | 0 | printf ("opcode: %x, operand #%d not decoded\n", opcode, op_num); |
1495 | 0 | abort (); |
1496 | 0 | } |
1497 | 373k | } |
1498 | | /* end for op_num */ |
1499 | | |
1500 | 162k | if (!operands_ok) |
1501 | 12.7k | continue; |
1502 | | |
1503 | 149k | info->bytes_per_chunk = num_bits / 8; |
1504 | 149k | info->fprintf_func (info->stream, "%s", parallel); |
1505 | 149k | info->fprintf_func (info->stream, "%s%s%s", cond, opc->name, |
1506 | 149k | func_unit); |
1507 | 502k | for (op_num = 0; op_num < num_operands; op_num++) |
1508 | 352k | { |
1509 | 352k | info->fprintf_func (info->stream, "%c", (op_num == 0 ? ' ' : ',')); |
1510 | 352k | if (operands_pcrel[op_num]) |
1511 | 11.9k | info->print_address_func (operands_addresses[op_num], info); |
1512 | 340k | else |
1513 | 340k | info->fprintf_func (info->stream, "%s", operands[op_num]); |
1514 | 352k | } |
1515 | 149k | if (fetch_packet_header_based && header.prot) |
1516 | 3.24k | info->fprintf_func (info->stream, " || nop 5"); |
1517 | | |
1518 | 149k | return num_bits / 8; |
1519 | 162k | } |
1520 | | |
1521 | 78.2k | info->bytes_per_chunk = num_bits / 8; |
1522 | 78.2k | info->fprintf_func (info->stream, "<undefined instruction 0x%.*x>", |
1523 | 78.2k | (int) num_bits / 4, opcode); |
1524 | 78.2k | return num_bits / 8; |
1525 | 228k | } |