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