* mn10200-dis.c (disassemble): Mask off unwanted bits after
[deliverable/binutils-gdb.git] / opcodes / tic80-dis.c
CommitLineData
6357e7f6
FF
1/* Print TI TMS320C80 (MVP) instructions
2 Copyright 1996 Free Software Foundation, Inc.
3
4This file is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
a79d0193
FF
17
18#include <stdio.h>
19
20#include "ansidecl.h"
21#include "opcode/tic80.h"
22#include "dis-asm.h"
23
937fe722
FF
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)))
50965d0e 26#define R_SCALED(insn,op) ((((op) -> flags & TIC80_OPERAND_SCALED) != 0) && ((insn) & (1 << 11)))
937fe722 27
a79d0193
FF
28int
29print_insn_tic80 (memaddr, info)
30 bfd_vma memaddr;
31 struct disassemble_info *info;
32{
872dc6f0
FF
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;
937fe722 40 int close_paren;
872dc6f0
FF
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. */
872dc6f0
FF
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
937fe722
FF
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)
872dc6f0 136 {
937fe722
FF
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, "(");
872dc6f0
FF
147 }
148
149 /* Print the operand as directed by the flags. */
937fe722 150
872dc6f0
FF
151 if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
152 {
153 (*info -> fprintf_func) (info -> stream, "r%ld", value);
937fe722
FF
154 if (M_SI (insn[0], operand) || M_LI (insn[0], operand))
155 {
156 (*info -> fprintf_func) (info -> stream, ":m");
157 }
872dc6f0
FF
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 {
1f8c8c60 165 (*info -> print_address_func) (memaddr + 4 * value, info);
872dc6f0 166 }
1f8c8c60 167 else if ((operand -> flags & TIC80_OPERAND_BITNUM) != 0)
872dc6f0 168 {
1f8c8c60
FF
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 }
872dc6f0
FF
183 else
184 {
1f8c8c60
FF
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);
872dc6f0 281 }
872dc6f0
FF
282 }
283 else
284 {
285 if ((value > 999 || value < -999)
286 || operand -> flags & TIC80_OPERAND_BITFIELD)
287 {
288 (*info -> fprintf_func) (info -> stream, "%#lx", value);
289 }
290 else
291 {
292 (*info -> fprintf_func) (info -> stream, "%ld", value);
293 }
294 }
295
50965d0e
FF
296 /* If this is a scaled operand, then print the modifier */
297
298 if (R_SCALED (insn[0], operand))
299 {
300 (*info -> fprintf_func) (info -> stream, ":s");
301 }
302
937fe722
FF
303 /* If we printed an open paren before printing this operand, close
304 it now. The flag gets reset on each loop. */
872dc6f0 305
937fe722 306 if (close_paren)
872dc6f0 307 {
937fe722 308 (*info -> fprintf_func) (info -> stream, ")");
872dc6f0
FF
309 }
310 }
311 }
312
313 return (length);
a79d0193 314}
This page took 0.036061 seconds and 4 git commands to generate.