]> Git Repo - binutils.git/blame - opcodes/tic80-dis.c
* tic80-dis.c (M_SI, M_LI): Add macros to test for ":m" modifier bit
[binutils.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)))
26
a79d0193
FF
27int
28print_insn_tic80 (memaddr, info)
29 bfd_vma memaddr;
30 struct disassemble_info *info;
31{
872dc6f0
FF
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;
937fe722 39 int close_paren;
872dc6f0
FF
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. */
872dc6f0
FF
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
937fe722
FF
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)
872dc6f0 135 {
937fe722
FF
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, "(");
872dc6f0
FF
146 }
147
148 /* Print the operand as directed by the flags. */
937fe722 149
872dc6f0
FF
150 if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
151 {
152 (*info -> fprintf_func) (info -> stream, "r%ld", value);
937fe722
FF
153 if (M_SI (insn[0], operand) || M_LI (insn[0], operand))
154 {
155 (*info -> fprintf_func) (info -> stream, ":m");
156 }
872dc6f0
FF
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 {
1f8c8c60 164 (*info -> print_address_func) (memaddr + 4 * value, info);
872dc6f0 165 }
1f8c8c60 166 else if ((operand -> flags & TIC80_OPERAND_BITNUM) != 0)
872dc6f0 167 {
1f8c8c60
FF
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 }
872dc6f0
FF
182 else
183 {
1f8c8c60
FF
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);
872dc6f0 280 }
872dc6f0
FF
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
937fe722
FF
295 /* If we printed an open paren before printing this operand, close
296 it now. The flag gets reset on each loop. */
872dc6f0 297
937fe722 298 if (close_paren)
872dc6f0 299 {
937fe722 300 (*info -> fprintf_func) (info -> stream, ")");
872dc6f0
FF
301 }
302 }
303 }
304
305 return (length);
a79d0193 306}
This page took 0.055037 seconds and 4 git commands to generate.