1 // license:BSD-3-Clause
2 // copyright-holders:Tony La Porta
3 /**************************************************************************\
4 * Texas Instruments TMS32010 DSP Disassembler *
5 * *
6 * Copyright Tony La Porta *
7 * To be used with TMS32010 DSP Emulator engine. *
8 * *
9 * Many thanks to those involved in the i8039 Disassembler *
10 * as this was based on it. *
11 * *
12 * *
13 * *
14 * A Memory address *
15 * B Branch Address for Branch instructions (Requires next opcode read) *
16 * D Immediate byte load *
17 * K Immediate bit load *
18 * W Immediate word load (Actually 13 bit) *
19 * M AR[x] register modification type (for indirect addressing) *
20 * N ARP register to change ARP pointer to (for indirect addressing) *
21 * P I/O port address number *
22 * R AR[R] register to use *
23 * S Shift ALU left *
24 * *
25 \**************************************************************************/
26
27 #include "emu.h"
28 #include "32010dsm.h"
29
30 #include <cctype>
31 #include <stdexcept>
32
33
34 const char *const tms32010_disassembler::arith[4] = { "*" , "*-" , "*+" , "??" } ;
35 const char *const tms32010_disassembler::nextar[4] = { ",AR0" , ",AR1" , "" , "" } ;
36
37
38 const char *const tms32010_disassembler::TMS32010Formats[] = {
39 "0000ssss0aaaaaaa", "add %A%S",
40 "0000ssss10mmn00n", "add %M%S%N",
41 "0001ssss0aaaaaaa", "sub %A%S",
42 "0001ssss10mmn00n", "sub %M%S%N",
43 "0010ssss0aaaaaaa", "lac %A%S",
44 "0010ssss10mmn00n", "lac %M%S%N",
45 "0011000r0aaaaaaa", "sar %R,%A",
46 "0011000r10mmn00n", "sar %R%M%N",
47 "0011100r0aaaaaaa", "lar %R,%A",
48 "0011100r10mmn00n", "lar %R%M%N",
49 "01000ppp0aaaaaaa", "in %A,%P",
50 "01000ppp10mmn00n", "in %M,%P%N",
51 "01001ppp0aaaaaaa", "out %A,%P",
52 "01001ppp10mmn00n", "out %M,%P%N",
53 "01010sss0aaaaaaa", "sacl %A", /* This instruction has a shift but */
54 "01010sss10mmn00n", "sacl %M%N", /* is documented as not performed */
55 "01011sss0aaaaaaa", "sach %A%S",
56 "01011sss10mmn00n", "sach %M%S%N",
57 "011000000aaaaaaa", "addh %A",
58 "0110000010mmn00n", "addh %M%N",
59 "011000010aaaaaaa", "adds %A",
60 "0110000110mmn00n", "adds %M%N",
61 "011000100aaaaaaa", "subh %A",
62 "0110001010mmn00n", "subh %M%N",
63 "011000110aaaaaaa", "subs %A",
64 "0110001110mmn00n", "subs %M%N",
65 "011001000aaaaaaa", "subc %A",
66 "0110010010mmn00n", "subc %M%N",
67 "011001010aaaaaaa", "zalh %A",
68 "0110010110mmn00n", "zalh %M%N",
69 "011001100aaaaaaa", "zals %A",
70 "0110011010mmn00n", "zals %M%N",
71 "011001110aaaaaaa", "tblr %A",
72 "0110011110mmn00n", "tblr %M%N",
73 "011010001000000k", "larp %K",
74 "011010000aaaaaaa", "mar %A", /* Actually this is executed as a NOP */
75 /* "0110100010mmn00n", "mar %M%N", */
76 /* MAR indirect has been expanded out to all its variations because one of */
77 /* its opcodes is the same as LARP (actually performs the same function) */
78
79 "0110100010001000", "mar *",
80 "0110100010001001", "mar *",
81 "0110100010010000", "mar *-,AR0",
82 "0110100010010001", "mar *-,AR1",
83 "0110100010011000", "mar *-",
84 "0110100010011001", "mar *-",
85 "0110100010100000", "mar *+,AR0",
86 "0110100010100001", "mar *+,AR1",
87 "0110100010101000", "mar *+",
88 "0110100010101001", "mar *+",
89 "0110100010110000", "mar ??,AR0",
90 "0110100010110001", "mar ??,AR1",
91 "0110100010111000", "mar ??",
92 "0110100010111001", "mar ??",
93
94 "011010010aaaaaaa", "dmov %A",
95 "0110100110mmn00n", "dmov %M%N",
96 "011010100aaaaaaa", "lt %A",
97 "0110101010mmn00n", "lt %M%N",
98 "011010110aaaaaaa", "ltd %A",
99 "0110101110mmn00n", "ltd %M%N",
100 "011011000aaaaaaa", "lta %A",
101 "0110110010mmn00n", "lta %M%N",
102 "011011010aaaaaaa", "mpy %A",
103 "0110110110mmn00n", "mpy %M%N",
104 "011011100000000k", "ldpk %K",
105 "011011110aaaaaaa", "ldp %A",
106 "0110111110mmn00n", "ldp %M%N",
107 "0111000rdddddddd", "lark %R,%D",
108 "011110000aaaaaaa", "xor %A",
109 "0111100010mmn00n", "xor %M%N",
110 "011110010aaaaaaa", "and %A",
111 "0111100110mmn00n", "and %M%N",
112 "011110100aaaaaaa", "or %A",
113 "0111101010mmn00n", "or %M%N",
114 "011110110aaaaaaa", "lst %A",
115 "0111101110mmn00n", "lst %M%N",
116 "011111000aaaaaaa", "sst %A",
117 "0111110010mmn00n", "sst %M%N",
118 "011111010aaaaaaa", "tblw %A",
119 "0111110110mmn00n", "tblw %M%N",
120 "01111110dddddddd", "lack %D",
121 "0111111110000000", "nop", /* 7F80 */
122 "0111111110000001", "dint",
123 "0111111110000010", "eint",
124 "0111111110001000", "abs", /* 7F88 */
125 "0111111110001001", "zac",
126 "0111111110001010", "rovm",
127 "0111111110001011", "sovm",
128 "0111111110001100", "cala",
129 "0111111110001101", "ret",
130 "0111111110001110", "pac",
131 "0111111110001111", "apac",
132 "0111111110010000", "spac",
133 "0111111110011100", "push",
134 "0111111110011101", "pop", /* 7F9D */
135 "100wwwwwwwwwwwww", "mpyk %W",
136 "1111010000000000bbbbbbbbbbbbbbbb", "banz %B",
137 "1111010100000000bbbbbbbbbbbbbbbb", "bv %B",
138 "1111011000000000bbbbbbbbbbbbbbbb", "bioz %B",
139 "1111100000000000bbbbbbbbbbbbbbbb", "call %B",
140 "1111100100000000bbbbbbbbbbbbbbbb", "b %B",
141 "1111101000000000bbbbbbbbbbbbbbbb", "blz %B",
142 "1111101100000000bbbbbbbbbbbbbbbb", "blez %B",
143 "1111110000000000bbbbbbbbbbbbbbbb", "bgz %B",
144 "1111110100000000bbbbbbbbbbbbbbbb", "bgez %B",
145 "1111111000000000bbbbbbbbbbbbbbbb", "bnz %B",
146 "1111111100000000bbbbbbbbbbbbbbbb", "bz %B",
147 nullptr
148 };
149
tms32010_disassembler()150 tms32010_disassembler::tms32010_disassembler()
151 {
152 const char *p;
153 const char *const *ops;
154 u16 mask, bits;
155 int bit;
156 int i;
157
158 ops = TMS32010Formats; i = 0;
159 while (*ops)
160 {
161 p = *ops;
162 mask = 0; bits = 0; bit = 15;
163 while (*p && bit >= 0)
164 {
165 switch (*p++)
166 {
167 case '1': mask |= 1<<bit; bits |= 1<<bit; bit--; break;
168 case '0': mask |= 1<<bit; bit--; break;
169 case ' ': break;
170 case 'a':
171 case 'b':
172 case 'd':
173 case 'k':
174 case 'm':
175 case 'n':
176 case 'p':
177 case 'r':
178 case 's':
179 case 'w':
180 bit--;
181 break;
182 default:
183 throw std::logic_error(util::string_format("Invalid instruction encoding '%s %s'\n", ops[0],ops[1]));
184 }
185 }
186 if (bit != -1 )
187 {
188 throw std::logic_error(util::string_format("not enough bits in encoding '%s %s' %d\n", ops[0],ops[1],bit));
189 }
190 while (isspace((uint8_t)*p)) p++;
191 Op.emplace_back(mask, bits, *p, ops[0], ops[1]);
192
193 ops += 2;
194 i++;
195 }
196 }
197
disassemble(std::ostream & stream,offs_t pc,const data_buffer & opcodes,const data_buffer & params)198 offs_t tms32010_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer ¶ms)
199 {
200 uint32_t flags = 0;
201 int a, b, d, k, m, n, p, r, s, w; /* these can all be filled in by parsing an instruction */
202 int i;
203 int op;
204 int cnt = 1;
205 int code;
206 int bit;
207 //char *buffertmp;
208 const char *cp; /* character pointer in OpFormats */
209
210 op = -1; /* no matching opcode */
211 code = opcodes.r16(pc);
212 for ( i = 0; i < int(Op.size()); i++)
213 {
214 if ((code & Op[i].mask) == Op[i].bits)
215 {
216 if (op != -1)
217 {
218 osd_printf_debug("Error: opcode %04Xh matches %d (%s) and %d (%s)\n",
219 code,i,Op[i].fmt,op,Op[op].fmt);
220 }
221 op = i;
222 }
223 }
224 if (op == -1)
225 {
226 util::stream_format(stream, "dw %04Xh *(invalid op)", code);
227 return cnt | SUPPORTED;
228 }
229 //buffertmp = buffer;
230 if (Op[op].extcode)
231 {
232 bit = 31;
233 code <<= 16;
234 code |= opcodes.r16(pc+1);
235 cnt++;
236 }
237 else
238 {
239 bit = 15;
240 }
241
242 /* shift out operands */
243 cp = Op[op].parse;
244 a = b = d = k = m = n = p = r = s = w = 0;
245
246 while (bit >= 0)
247 {
248 /* osd_printf_debug("{%c/%d}",*cp,bit); */
249 switch(*cp)
250 {
251 case 'a': a <<=1; a |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
252 case 'b': b <<=1; b |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
253 case 'd': d <<=1; d |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
254 case 'k': k <<=1; k |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
255 case 'm': m <<=1; m |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
256 case 'n': n <<=1; n |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
257 case 'p': p <<=1; p |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
258 case 'r': r <<=1; r |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
259 case 's': s <<=1; s |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
260 case 'w': w <<=1; w |= ((code & (1<<bit)) ? 1 : 0); bit--; break;
261 case ' ': break;
262 case '1': case '0': bit--; break;
263 case '\0': throw std::logic_error(util::string_format("premature end of parse string, opcode %x, bit = %d\n",code,bit));
264 }
265 cp++;
266 }
267
268 /* now traverse format string */
269 cp = Op[op].fmt;
270
271 if (!strncmp(cp, "cal", 3))
272 flags = STEP_OVER;
273 else if (!strncmp(cp, "ret", 3))
274 flags = STEP_OUT;
275
276 while (*cp)
277 {
278 if (*cp == '%')
279 {
280 char num[20];
281 cp++;
282 switch (*cp++)
283 {
284 case 'A': sprintf(num,"%02Xh",a); break; // was $%02X
285 case 'B': sprintf(num,"%04Xh",b); break; // was $%04X
286 case 'D': sprintf(num,"%02Xh",d); break;
287 case 'K': sprintf(num,"%d",k); break;
288 case 'N': sprintf(num,"%s",nextar[n]); break;
289 case 'M': sprintf(num,"%s",arith[m]); break;
290 case 'P': sprintf(num,"PA%d",p); break;
291 case 'R': sprintf(num,"AR%d",r); break;
292 case 'S': sprintf(num,",%d",s); break;
293 case 'W': sprintf(num,"%04Xh",w); break;
294 default:
295 throw std::logic_error(util::string_format("illegal escape character in format '%s'\n",Op[op].fmt));
296 }
297 stream << num;
298 }
299 else
300 {
301 stream << *cp++;
302 }
303 }
304 return cnt | flags | SUPPORTED;
305 }
306
opcode_alignment() const307 u32 tms32010_disassembler::opcode_alignment() const
308 {
309 return 1;
310 }
311
312