d930c80dcc6f7ee08efa39d39ce8d7764d3ed853
[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 int
25 print_insn_tic80 (memaddr, info)
26 bfd_vma memaddr;
27 struct disassemble_info *info;
28 {
29 bfd_byte buffer[4];
30 int status;
31 unsigned long insn[2];
32 const struct tic80_opcode *opcode;
33 const struct tic80_opcode *opcode_end;
34 const unsigned char *opindex;
35 const struct tic80_operand *operand;
36 int need_comma;
37 int need_paren;
38 int length = 4;
39
40 status = (*info->read_memory_func) (memaddr, buffer, 4, info);
41 if (status != 0)
42 {
43 (*info->memory_error_func) (status, memaddr, info);
44 return -1;
45 }
46
47 if (info -> endian == BFD_ENDIAN_LITTLE)
48 {
49 insn[0] = bfd_getl32 (buffer);
50 }
51 else if (info -> endian == BFD_ENDIAN_BIG)
52 {
53 insn[0] = bfd_getb32 (buffer);
54 }
55 else
56 {
57 /* FIXME: Should probably just default to one or the other */
58 abort ();
59 }
60
61 /* Find the first opcode match in the opcodes table. FIXME: there should
62 be faster ways to find one (hash table or binary search), but don't
63 worry too much about it until other TIc80 support is finished. */
64
65 opcode_end = tic80_opcodes + tic80_num_opcodes;
66 for (opcode = tic80_opcodes; opcode < opcode_end; opcode++)
67 {
68 if ((insn[0] & opcode -> mask) == opcode -> opcode)
69 {
70 break;
71 }
72 }
73
74 if (opcode == opcode_end)
75 {
76 /* No match found, just print the bits as a .word directive */
77 (*info -> fprintf_func) (info -> stream, ".word %#08lx", insn[0]);
78 }
79 else
80 {
81 /* Match found, decode the instruction. */
82 (*info -> fprintf_func) (info -> stream, "%s", opcode -> name);
83
84 /* Now extract and print the operands. */
85 need_comma = 0;
86 need_paren = 0;
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 (need_comma)
131 {
132 (*info -> fprintf_func) (info -> stream, ",");
133 need_comma = 0;
134 }
135
136 /* Print the operand as directed by the flags. */
137 if ((operand -> flags & TIC80_OPERAND_GPR) != 0)
138 {
139 (*info -> fprintf_func) (info -> stream, "r%ld", value);
140 }
141 else if ((operand -> flags & TIC80_OPERAND_FPA) != 0)
142 {
143 (*info -> fprintf_func) (info -> stream, "a%ld", value);
144 }
145 else if ((operand -> flags & TIC80_OPERAND_RELATIVE) != 0)
146 {
147 (*info -> print_address_func) (memaddr + value, info);
148 }
149 else if ((operand -> flags & TIC80_OPERAND_CC_SZ) != 0)
150 {
151 #if 0 /* FIXME */
152 if (operand -> bits == 3)
153 (*info -> fprintf_func) (info -> stream, "cr%d", value);
154 else
155 {
156 static const char *cbnames[4] = { "lt", "gt", "eq", "so" };
157 int cr;
158 int cc;
159
160 cr = value >> 2;
161 if (cr != 0)
162 (*info -> fprintf_func) (info -> stream, "4*cr%d", cr);
163 cc = value & 3;
164 if (cc != 0)
165 {
166 if (cr != 0)
167 (*info -> fprintf_func) (info -> stream, "+");
168 (*info -> fprintf_func) (info -> stream, "%s", cbnames[cc]);
169 }
170 }
171 #endif
172 }
173 else
174 {
175 if ((value > 999 || value < -999)
176 || operand -> flags & TIC80_OPERAND_BITFIELD)
177 {
178 (*info -> fprintf_func) (info -> stream, "%#lx", value);
179 }
180 else
181 {
182 (*info -> fprintf_func) (info -> stream, "%ld", value);
183 }
184 }
185
186 if (need_paren)
187 {
188 (*info -> fprintf_func) (info -> stream, ")");
189 need_paren = 0;
190 }
191
192 if ((operand -> flags & TIC80_OPERAND_PARENS) == 0)
193 {
194 need_comma = 1;
195 }
196 else
197 {
198 (*info -> fprintf_func) (info -> stream, "(");
199 need_paren = 1;
200 }
201 }
202 }
203
204 return (length);
205 }