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 &params)
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