02a4110f810d81c7b93fed7c5ccf245bb5d91d0f
[deliverable/binutils-gdb.git] / opcodes / tic80-dis.c
1 /* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996 Free Software Foundation, Inc.
3
4 This file is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18 #include <stdio.h>
19
20 #include "ansidecl.h"
21 #include "opcode/tic80.h"
22 #include "dis-asm.h"
23
24 #define M_SI(insn,op) ((((op) -> flags & TIC80_OPERAND_M_SI) != 0) && ((insn) & (1 << 17)))
25 #define M_LI(insn,op) ((((op) -> flags & TIC80_OPERAND_M_LI) != 0) && ((insn) & (1 << 15)))
26 #define R_SCALED(insn,op) ((((op) -> flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
27
28 int
29 print_insn_tic80 (memaddr, info)
30 bfd_vma memaddr;
31 struct disassemble_info *info;
32 {
33 bfd_byte buffer[4];
34 int status;
35 unsigned long insn[2];
36 const struct tic80_opcode *opcode;
37 const struct tic80_opcode *opcode_end;
38 const unsigned char *opindex;
39 const struct tic80_operand *operand;
40 int close_paren;
41 int length = 4;
42
43 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
44 if (status != 0)
45 {
46 (*info->memory_error_func) (status, memaddr, info);
47 return -1;
48 }
49
50 if (info -> endian == BFD_ENDIAN_LITTLE)
51 {
52 insn[0] = bfd_getl32 (buffer);
53 }
54 else if (info -> endian == BFD_ENDIAN_BIG)
55 {
56 insn[0] = bfd_getb32 (buffer);
57 }
58 else
59 {
60 /* FIXME: Should probably just default to one or the other */
61 abort ();
62 }
63
64 /* Find the first opcode match in the opcodes table. FIXME: there should
65 be faster ways to find one (hash table or binary search), but don't
66 worry too much about it until other TIc80 support is finished. */
67
68 opcode_end = tic80_opcodes + tic80_num_opcodes;
69 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
70 {
71 if ((insn[0] & opcode -> mask) == opcode -> opcode)
72 {
73 break;
74 }
75 }
76
77 if (opcode == opcode_end)
78 {
79 /* No match found, just print the bits as a .word directive */
80 (*info -> fprintf_func) (info -> stream, ".word %#08lx", insn[0]);
81 }
82 else
83 {
84 /* Match found, decode the instruction. */
85 (*info -> fprintf_func) (info -> stream, "%s", opcode -> name);
86
87 /* Now extract and print the operands. */
88 if (opcode -> operands[0] != 0)
89 {
90 (*info -> fprintf_func) (info -> stream, "\t");
91 }
92 for (opindex = opcode -> operands; *opindex != 0; opindex++)
93 {
94 long value;
95
96 operand = tic80_operands + *opindex;
97
98 /* Extract the value from the instruction. */
99 if (operand -> extract)
100 {
101 value = (*operand -> extract) (insn[0], (int *) NULL);
102 }
103 else if (operand -> bits == 32)
104 {
105 status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info);
106 if (status != 0)
107 {
108 (*info->memory_error_func) (status, memaddr, info);
109 return -1;
110 }
111
112 if (info -> endian == BFD_ENDIAN_LITTLE)
113 {
114 insn[1] = bfd_getl32 (buffer);
115 }
116 else if (info -> endian == BFD_ENDIAN_BIG)
117 {
118 insn[1] = bfd_getb32 (buffer);
119 }
120 value = (long) insn[1];
121 length += 4;
122 }
123 else
124 {
125 value = (insn[0] >> operand -> shift) & ((1 << operand -> bits) - 1);
126 if ((operand -> flags & TIC80_OPERAND_SIGNED) != 0
127 && (value & (1 << (operand -> bits - 1))) != 0)
128 value -= 1 << operand -> bits;
129 }
130
131 /* If this operand is enclosed in parenthesis, then print
132 the open paren, otherwise just print the regular comma
133 separator, except for the first operand. */
134
135 if ((operand -> flags & TIC80_OPERAND_PARENS) == 0)
136 {
137 close_paren = 0;
138 if (opindex != opcode -> operands)
139 {
140 (*info -> fprintf_func) (info -> stream, ",");
141 }
142 }
143 else
144 {
145 close_paren = 1;
146 (*info -> fprintf_func) (info -> stream, "(");
147 }
148
149 /* Print the operand as directed by the flags. */
150
151 if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
152 {
153 (*info -> fprintf_func) (info -> stream, "r%ld", value);
154 if (M_SI (insn[0], operand) || M_LI (insn[0], operand))
155 {
156 (*info -> fprintf_func) (info -> stream, ":m");
157 }
158 }
159 else if ((operand -> flags & TIC80_OPERAND_FPA) != 0)
160 {
161 (*info -> fprintf_func) (info -> stream, "a%ld", value);
162 }
163 else if ((operand -> flags & TIC80_OPERAND_RELATIVE) != 0)
164 {
165 (*info -> print_address_func) (memaddr + 4 * value, info);
166 }
167 else if ((operand -> flags & TIC80_OPERAND_BITNUM) != 0)
168 {
169 char *syms[30] = {
170 "eq.b", "ne.b", "gt.b", "le.b", "lt.b", "ge.b",
171 "hi.b", "ls.b", "lo.b", "hs.b", "eq.h", "ne.h",
172 "gt.h", "le.h", "lt.h", "ge.h", "hi.h", "ls.h",
173 "lo.h", "hs.h", "eq.w", "ne.w", "gt.w", "le.w",
174 "lt.w", "ge.w", "hi.w", "ls.w", "lo.w", "hs.w"
175 };
176 int bitnum = ~value & 0x1F;
177
178 if (bitnum < 30)
179 {
180 /* Found a value within range */
181 (*info -> fprintf_func) (info -> stream, "%s", syms[bitnum]);
182 }
183 else
184 {
185 /* Not in range, just print as bit number */
186 (*info -> fprintf_func) (info -> stream, "%ld", bitnum);
187 }
188 }
189 else if ((operand -> flags & TIC80_OPERAND_CC) != 0)
190 {
191 char *syms[24] = {
192 "nev.b", "gt0.b", "eq0.b", "ge0.b", "lt0.b", "ne0.b", "le0.b", "alw.b",
193 "nev.h", "gt0.h", "eq0.h", "ge0.h", "lt0.h", "ne0.h", "le0.h", "alw.h",
194 "nev.w", "gt0.w", "eq0.w", "ge0.w", "lt0.w", "ne0.w", "le0.w", "alw.w"
195 };
196 if (value < 24)
197 {
198 /* Found a value within range */
199 (*info -> fprintf_func) (info -> stream, "%s", syms[value]);
200 }
201 else
202 {
203 /* Not in range, just print as decimal digit. */
204 (*info -> fprintf_func) (info -> stream, "%ld", value);
205 }
206 }
207 else if ((operand -> flags & TIC80_OPERAND_CR) != 0)
208 {
209 char *tmp;
210 switch (value)
211 {
212 case 0: tmp = "EPC"; break;
213 case 1: tmp = "EIP"; break;
214 case 2: tmp = "CONFIG"; break;
215 case 4: tmp = "INTPEN"; break;
216 case 6: tmp = "IE"; break;
217 case 8: tmp = "FPST"; break;
218 case 0xA: tmp = "PPERROR"; break;
219 case 0xD: tmp = "PKTREQ"; break;
220 case 0xE: tmp = "TCOUNT"; break;
221 case 0xF: tmp = "TSCALE"; break;
222 case 0x10: tmp = "FLTOP"; break;
223 case 0x11: tmp = "FLTADR"; break;
224 case 0x12: tmp = "FLTTAG"; break;
225 case 0x13: tmp = "FLTDTL"; break;
226 case 0x14: tmp = "FLTDTH"; break;
227 case 0x20: tmp = "SYSSTK"; break;
228 case 0x21: tmp = "SYSTMP"; break;
229 case 0x30: tmp = "MPC"; break;
230 case 0x31: tmp = "MIP"; break;
231 case 0x33: tmp = "ECOMCNTL"; break;
232 case 0x34: tmp = "ANASTAT"; break;
233 case 0x39: tmp = "BRK1"; break;
234 case 0x3A: tmp = "BRK2"; break;
235 case 0x200: tmp = "ITAG0"; break;
236 case 0x201: tmp = "ITAG1"; break;
237 case 0x202: tmp = "ITAG2"; break;
238 case 0x203: tmp = "ITAG3"; break;
239 case 0x204: tmp = "ITAG4"; break;
240 case 0x205: tmp = "ITAG5"; break;
241 case 0x206: tmp = "ITAG6"; break;
242 case 0x207: tmp = "ITAG7"; break;
243 case 0x208: tmp = "ITAG8"; break;
244 case 0x209: tmp = "ITAG9"; break;
245 case 0x20A: tmp = "ITAG10"; break;
246 case 0x20B: tmp = "ITAG11"; break;
247 case 0x20C: tmp = "ITAG12"; break;
248 case 0x20D: tmp = "ITAG13"; break;
249 case 0x20E: tmp = "ITAG14"; break;
250 case 0x20F: tmp = "ITAG15"; break;
251 case 0x300: tmp = "ILRU"; break;
252 case 0x400: tmp = "DTAG0"; break;
253 case 0x401: tmp = "DTAG1"; break;
254 case 0x402: tmp = "DTAG2"; break;
255 case 0x403: tmp = "DTAG3"; break;
256 case 0x404: tmp = "DTAG4"; break;
257 case 0x405: tmp = "DTAG5"; break;
258 case 0x406: tmp = "DTAG6"; break;
259 case 0x407: tmp = "DTAG7"; break;
260 case 0x408: tmp = "DTAG8"; break;
261 case 0x409: tmp = "DTAG9"; break;
262 case 0x40A: tmp = "DTAG10"; break;
263 case 0x40B: tmp = "DTAG11"; break;
264 case 0x40C: tmp = "DTAG12"; break;
265 case 0x40D: tmp = "DTAG13"; break;
266 case 0x40E: tmp = "DTAG14"; break;
267 case 0x40F: tmp = "DTAG15"; break;
268 case 0x500: tmp = "DLRU"; break;
269 case 0x4000: tmp = "IN0P"; break;
270 case 0x4001: tmp = "IN1P"; break;
271 case 0x4002: tmp = "OUTP"; break;
272 default: tmp = NULL; break;
273 }
274 if (tmp != NULL)
275 {
276 (*info -> fprintf_func) (info -> stream, "%s", tmp);
277 }
278 else
279 {
280 (*info -> fprintf_func) (info -> stream, "%#lx", value);
281 }
282 }
283 else if ((operand -> flags & TIC80_OPERAND_FLOAT) != 0)
284 {
285 /* FIXME: depends upon sizeof (long) == sizeof (float) */
286 union { float f; long l; } fval;
287
288 fval.l = value;
289 (*info -> fprintf_func) (info -> stream, "%g", fval.f);
290 }
291 else
292 {
293 if ((value > 999 || value < -999)
294 || operand -> flags & TIC80_OPERAND_BITFIELD)
295 {
296 (*info -> fprintf_func) (info -> stream, "%#lx", value);
297 }
298 else
299 {
300 (*info -> fprintf_func) (info -> stream, "%ld", value);
301 }
302 }
303
304 /* If this is a scaled operand, then print the modifier */
305
306 if (R_SCALED (insn[0], operand))
307 {
308 (*info -> fprintf_func) (info -> stream, ":s");
309 }
310
311 /* If we printed an open paren before printing this operand, close
312 it now. The flag gets reset on each loop. */
313
314 if (close_paren)
315 {
316 (*info -> fprintf_func) (info -> stream, ")");
317 }
318 }
319 }
320
321 return (length);
322 }
This page took 0.040556 seconds and 4 git commands to generate.