1 /*
2 * Copyright (c) 2015, Marcos Medeiros
3 * Licensed under BSD 3-clause.
4 */
5 #include <string>
6 #include <vector>
7 #include "tms34010.h"
8 #include "memhandler.h"
9
10 namespace tms
11 {
12
13 #define READ_WORD(addr) tms::read_word(addr)
14 #define READ_DWORD(addr) (READ_WORD(addr) | (READ_WORD(addr + 16) << 16))
15
16 const int dasm_buf_size = 128;
17 const int dasm_pc_size = 32;
18
19 static const char *reg_names[32] =
20 {
21 "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
22 "a8", "a9", "a10", "a11", "a12", "a13", "a14", "sp",
23 "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
24 "b8", "b9", "b10", "b11", "b12", "b13", "b14", "sp",
25 };
26
27 #define BKW_DIR (st.opcode & (1 << 10))
28 #define OFFS ((st.opcode >> 5) & 0x1F)
29 #define K fw_lut[((st.opcode >> 5) & 0x1F)]
30 #define FS fw_lut[st.opcode & 0x1F]
31 #define KN ((~st.opcode >> 5) & 0x1F)
32 #define K2C ((-K) & 0x1F)
33 #define M_BIT (st.opcode & (1 << 9))
34 #define R_BIT (st.opcode & 0x10)
35 #define RS_ (((st.opcode >> 5) & 0xF) | R_BIT)
36 #define RD_ ((st.opcode & 0xF) | R_BIT)
37 #define NF (st.opcode & 0x1F)
38 #define RS_n ((st.opcode >> 5) & 0xF)
39 #define RD_n (st.opcode & 0xF)
40
41 #define RS reg_names[RS_]
42 #define RD reg_names[RD_]
43 #define IW st.iw
44 #define IW2 st.iw2
45 #define IL st.il
46 #define IL2 st.il2
47 #define W st.words
48 #define OP st.opcode
49
50 #define WDISP (st.pc + ((short)(IW)) * 16) + 32
51 #define BDISP (st.pc + ((char)(OP & 0xFF) * 16)) + 16
52
53 #define DASM(...) snprintf(st.buf, dasm_buf_size, __VA_ARGS__)
54
55 struct dasm_state {
56 dword pc;
57 word opcode;
58 char buf[dasm_buf_size];
59 int words;
60 word iw;
61 word iw2;
62 dword il;
63 dword il2;
dasm_statetms::dasm_state64 dasm_state() {
65 buf[0] = '\0';
66 }
67 };
68
69
reg_list(word opcode,word data)70 static std::string reg_list(word opcode, word data)
71 {
72 int inc = (opcode & 0x10) ? 16 : 0;
73 std::vector<std::string> regs;
74 regs.reserve(16);
75
76
77 for (int i = 0; i < 16; i++) {
78 if (data & 0x8000)
79 regs.push_back(reg_names[inc + i]);
80 data <<= 1;
81 }
82
83
84 std::string s;
85 s.reserve(100);
86 for (size_t i = 0; i < regs.size(); i++) {
87 s.append(regs[i]);
88 if (i != regs.size() - 1)
89 s.append(",");
90 }
91
92 return s;
93 }
94
reg_list_inv(word opcode,word data)95 static std::string reg_list_inv(word opcode, word data)
96 {
97 int inc = (opcode & 0x10) ? 16 : 0;
98 std::vector<std::string> regs;
99 regs.reserve(16);
100
101
102 for (int i = 0; i < 16; i++) {
103 if (data & 1)
104 regs.push_back(reg_names[inc + i]);
105 data >>= 1;
106 }
107
108
109 std::string s;
110 s.reserve(100);
111 for (int i = 0; i < regs.size(); i++) {
112 s.append(regs[i]);
113 if (i != regs.size() - 1)
114 s.append(",");
115 }
116
117 return s;
118 }
119
dasm_prefix_0000(dasm_state & st)120 static void dasm_prefix_0000(dasm_state &st)
121 {
122 switch ((OP >> 8) & 0xF) {
123 case 0x0:
124 if (((OP >> 5) & 7) == 1)
125 DASM("rev %s", RD);
126 else
127 DASM("invalid opcode [%04Xh] 0000", OP);
128 break;
129
130 case 0x1:
131 switch ((OP >> 5) & 7) {
132 case 0: DASM("emu"); break;
133 case 1: DASM("exgpc %s", RD); break;
134 case 2: DASM("getpc %s", RD); break;
135 case 3: DASM("jump %s", RD); break;
136 case 4: DASM("getst %s", RD); break;
137 case 5: DASM("putst %s", RD); break;
138 case 6: DASM("popst"); break;
139 case 7: DASM("pushst"); break;
140 }
141 break;
142
143 case 0x2:
144 DASM("invalid opcode [%04Xh] 0000 010X", OP);
145 break;
146
147 case 0x3:
148 switch ((OP >> 5) & 7) {
149 case 0: DASM("nop"); break;
150 case 1: DASM("clrc"); break;
151 case 2: DASM("movb @%08Xh, @%08x", IL, IL2); W+=4; break;
152 case 3: DASM("dint"); break;
153 case 4: DASM("abs %s", RD); break;
154 case 5: DASM("neg %s", RD); break;
155 case 6: DASM("negb %s", RD); break;
156 case 7: DASM("not %s", RD); break;
157 }
158 break;
159
160 case 0x4:
161 DASM("invalid opcode [%04Xh] 0000 0100", OP);
162 break;
163
164 case 0x5:
165 switch ((OP >> 5) & 7) {
166 case 0: DASM("sext %s, 0", RD); break;
167 case 1: DASM("zext %s, 0", RD); break;
168 case 2: DASM("setf %d, 0, 0", FS); break;
169 case 3: DASM("setf %d, 1, 0", FS); break;
170 case 4: DASM("move %s, @%08Xh, 0", RD, IL); W+=2; break;
171 case 5: DASM("move @%08Xh, %s, 0", IL, RD); W+=2; break;
172 case 6: DASM("move @%08Xh, @%08Xh, 0", IL, IL2); W+=4;break;
173 case 7: DASM("movb %s, @%08Xh", RD, IL); W+=2; break;
174 }
175 break;
176
177 case 0x6:
178 DASM("invalid opcode [%04Xh]", OP);
179 break;
180
181 case 0x7:
182 switch ((OP >> 5) & 7) {
183 case 0: DASM("sext %s, 1", RD); break;
184 case 1: DASM("zext %s, 1", RD); break;
185 case 2: DASM("setf %d, 0, 1", FS); break;
186 case 3: DASM("setf %d, 1, 1", FS); break;
187 case 4: DASM("move %s, @%08Xh, 1", RD, IL); W+=2; break;
188 case 5: DASM("move @%08Xh, %s, 1", IL, RD); W+=2; break;
189 case 6: DASM("move @%08Xh, @%08Xh, 1", IL, IL2); W+=4;break;
190 case 7: DASM("movb @%08Xh, %s", IL, RD); W+=2; break;
191 }
192 break;
193
194 case 0x8:
195 DASM("invalid opcode [%04Xh]", OP);
196 break;
197
198 case 0x9:
199 switch ((OP >> 5) & 7) {
200 case 0: DASM("trap %Xh", OP & 0x1F); break;
201 case 1: DASM("call %s", RD); break;
202 case 2: DASM("reti"); break;
203 case 3: DASM("rets 0x%d", OP & 0x1F); break;
204 case 4: DASM("mmtm %s, %s", RD, reg_list(OP,IW).c_str()); W++; break;
205 case 5: DASM("mmfm %s, %s", RD, reg_list_inv(OP,IW).c_str()); W++; break;
206 case 6: DASM("movi %04Xh, %s", IW, RD); W++; break;
207 case 7: DASM("movi %08Xh, %s", IL, RD); W+=2; break;
208 }
209 break;
210
211 case 0xA:
212 DASM("invalid opcode [%04Xh]", OP);
213 break;
214
215 case 0xB:
216 switch ((OP >> 5) & 7) {
217 case 0: DASM("addi %04Xh, %s", IW, RD); W++; break;
218 case 1: DASM("addi %08Xh, %s", IL, RD); W+=2; break;
219 case 2: DASM("cmpi %04Xh, %s", ~IW, RD); W++; break;
220 case 3: DASM("cmpi %08Xh, %s", ~IL, RD); W+=2; break;
221 case 4: DASM("andi %08Xh, %s", ~IL, RD); W+=2; break;
222 case 5: DASM("ori %08Xh, %s", IL, RD); W+=2; break;
223 case 6: DASM("xori %08Xh, %s", IL, RD); W+=2; break;
224 case 7: DASM("subi %08Xh, %s", ~IL, RD); W+=2; break;
225 }
226 break;
227
228 case 0xC:
229 DASM("invalid opcode [%04Xh]", OP);
230 break;
231
232 case 0xD:
233 switch ((OP >> 4) & 15) {
234 case 0x3: DASM("callr %08Xh", WDISP); W++; break;
235 case 0x5: DASM("calla %08Xh", IL); W+=2; break;
236 case 0x6: DASM("eint"); break;
237 case 0x8:
238 case 0x9: DASM("dsj %s, %08x", RD, WDISP); W++; break;
239 case 0xA:
240 case 0xB: DASM("dsjeq %s, %08x", RD, WDISP); W++; break;
241 case 0xC:
242 case 0xD: DASM("dsjne %s, %08x", RD, WDISP); W++; break;
243 case 0xE: DASM("setc"); break;
244 default:
245 DASM("invalid opcode [%04Xh] 0000 1101", OP);
246 break;
247 }
248 break;
249 case 0xE:
250 DASM("invalid opcode [%04Xh]", OP);
251 break;
252
253 case 0xF:
254 switch ((OP >> 4) & 0xF) {
255 case 0x0: DASM("pixblt l, l"); break;
256 case 0x2: DASM("pixblt l, xy"); break;
257 case 0x4: DASM("pixblt xy, l"); break;
258 case 0x6: DASM("pixblt xy, xy"); break;
259 case 0x8: DASM("pixblt b, l"); break;
260 case 0xA: DASM("pixblt b, xy"); break;
261 case 0xC: DASM("fill l"); break;
262 case 0xE: DASM("fill xy"); break;
263 default:
264 DASM("invalid opcode [%04Xh] 0000 1111", OP);
265 break;
266 }
267 break;
268 }
269 }
270
dasm_prefix_0001(dasm_state & st)271 static void dasm_prefix_0001(dasm_state &st)
272 {
273 switch ((OP >> 10) & 3) {
274 case 0: if (K==1) DASM("inc %s", RD); else DASM("addk %d, %s", K, RD); break;
275 case 1: if (K==1) DASM("dec %s", RD); else DASM("subk %d, %s", K, RD); break;
276 case 2: DASM("movk %d, %s", K, RD); break;
277 case 3: DASM("btst %d, %s", K, RD); break;
278 }
279 }
280
dasm_prefix_0010(dasm_state & st)281 static void dasm_prefix_0010(dasm_state &st)
282 {
283 switch ((OP >> 10) & 3) {
284 case 0: DASM("sla %d, %s", K, RD); break;
285 case 1: DASM("sll %d, %s", K, RD); break;
286 case 2: DASM("sra %d, %s", K, RD); break;
287 case 3: DASM("srl %d, %s", K, RD); break;
288 }
289 }
290
dasm_prefix_0011(dasm_state & st)291 static void dasm_prefix_0011(dasm_state &st)
292 {
293 switch ((OP >> 10) & 3) {
294 case 0: DASM("rl %d, %s", K, RD); break;
295 case 1: DASM("invalid opcode [%04Xh] 0011", OP); break;
296 case 2:
297 case 3: {
298 int displace = OFFS * 16;
299 if (BKW_DIR)
300 displace = -displace;
301 DASM("dsjs %s, %08Xh", RD, st.pc + 16 + displace);
302 break;
303 }
304 }
305 }
306
dasm_prefix_0100(dasm_state & st)307 static void dasm_prefix_0100(dasm_state &st)
308 {
309 switch ((OP >> 9) & 7) {
310 case 0: DASM("add %s, %s", RS, RD); break;
311 case 1: DASM("addc %s, %s", RS, RD); break;
312 case 2: DASM("sub %s, %s", RS, RD); break;
313 case 3: DASM("subb %s, %s", RS, RD); break;
314 case 4: DASM("cmp %s, %s", RS, RD); break;
315 case 5: DASM("btst %s, %s", RS, RD); break;
316 case 6: DASM("move %s, %s", RS, RD); break;
317 case 7: {
318 DASM("move %s, %s", RS, R_BIT ? reg_names[RD_n] : reg_names[RD_n | 0x10]);
319 break;
320 }
321 }
322 }
323
dasm_prefix_0101(dasm_state & st)324 static void dasm_prefix_0101(dasm_state &st)
325 {
326 switch ((OP >> 9) & 7) {
327 case 0: DASM("and %s, %s", RS, RD); break;
328 case 1: DASM("andn %s, %s", RS, RD); break;
329 case 2: DASM("or %s, %s", RS, RD); break;
330 case 3: if (RS_==RD_) DASM("clr %s", RD); else DASM("xor %s, %s", RS, RD); break;
331 case 4: DASM("divs %s, %s", RS, RD); break;
332 case 5: DASM("divu %s, %s", RS, RD); break;
333 case 6: DASM("mpys %s, %s", RS, RD); break;
334 case 7: DASM("mpyu %s, %s", RS, RD); break;
335 }
336 }
337
dasm_prefix_0110(dasm_state & st)338 static void dasm_prefix_0110(dasm_state &st)
339 {
340 switch ((OP >> 9) & 7) {
341 case 0: DASM("sla %s, %s", RS, RD); break;
342 case 1: DASM("sll %s, %s", RS, RD); break;
343 case 2: DASM("sra %s, %s", RS, RD); break;
344 case 3: DASM("srl %s, %s", RS, RD); break;
345 case 4: DASM("rl %s, %s", RS, RD); break;
346 case 5: DASM("lmo %s, %s", RS, RD); break;
347 case 6: DASM("mods %s, %s", RS, RD); break;
348 case 7: DASM("modu %s, %s", RS, RD); break;
349 }
350 }
351
dasm_prefix_0111(dasm_state & st)352 static void dasm_prefix_0111(dasm_state &st)
353 {
354 DASM("invalid opcode [%04Xh] 0111", OP);
355 }
356
dasm_prefix_1000(dasm_state & st)357 static void dasm_prefix_1000(dasm_state &st)
358 {
359 switch ((OP >> 9) & 7) {
360 case 0: DASM("move %s, *%s, 0", RS, RD); break;
361 case 1: DASM("move %s, *%s, 1", RS, RD); break;
362 case 2: DASM("move *%s, %s, 0", RS, RD); break;
363 case 3: DASM("move *%s, %s, 1", RS, RD); break;
364 case 4: DASM("move *%s, *%s, 0", RS, RD); break;
365 case 5: DASM("move *%s, *%s, 1", RS, RD); break;
366 case 6: DASM("move %s, *%s", RS, RD); break;
367 case 7: DASM("move *%s, %s", RS, RD); break;
368 }
369 }
370
dasm_prefix_1001(dasm_state & st)371 static void dasm_prefix_1001(dasm_state &st)
372 {
373 switch ((OP >> 9) & 7) {
374 case 0: DASM("move %s, *%s+, 0", RS, RD); break;
375 case 1: DASM("move %s, *%s+, 1", RS, RD); break;
376 case 2: DASM("move *%s+, %s, 0", RS, RD); break;
377 case 3: DASM("move *%s+, %s, 1", RS, RD); break;
378 case 4: DASM("move *%s+, *%s+, 0", RS, RD); break;
379 case 5: DASM("move *%s+, *%s+, 1", RS, RD); break;
380 case 6: DASM("movb *%s, *%s", RS, RD); break;
381 case 7: DASM("invalid opcode [%04Xh] 1001", OP); break;
382 }
383 }
384
dasm_prefix_1010(dasm_state & st)385 static void dasm_prefix_1010(dasm_state &st)
386 {
387 switch ((OP >> 9) & 7) {
388 case 0: DASM("move %s, -*%s, 0", RS, RD); break;
389 case 1: DASM("move %s, -*%s, 1", RS, RD); break;
390 case 2: DASM("move -*%s, %s, 0", RS, RD); break;
391 case 3: DASM("move -*%s, %s, 1", RS, RD); break;
392 case 4: DASM("move -*%s, -*%s, 0", RS, RD); break;
393 case 5: DASM("move -*%s, -*%s, 1", RS, RD); break;
394 case 6: DASM("move %s, *%s(%Xh)", RS, RD, IW); W++; break;
395 case 7: DASM("move *%s(%Xh), %s", RS, IW, RD); W++; break;
396 }
397 }
398
dasm_prefix_1011(dasm_state & st)399 static void dasm_prefix_1011(dasm_state &st)
400 {
401 switch ((OP >> 9) & 7) {
402 case 0: DASM("move %s, *%s(%Xh), 0", RS, RD, IW); W++; break;
403 case 1: DASM("move %s, *%s(%Xh), 1", RS, RD, IW); W++; break;
404 case 2: DASM("move *%s(%Xh), %s, 0", RS, IW, RD); W++; break;
405 case 3: DASM("move *%s(%Xh), %s, 1", RS, IW, RD); W++; break;
406 case 4: DASM("move *%s(%Xh), *%s(%Xh), 0", RS, IW, RD, IW2); W+=2; break;
407 case 5: DASM("move *%s(%Xh), *%s(%Xh), 1", RS, IW, RD, IW2); W+=2; break;
408 case 6: DASM("movb *%s(%Xh), *%s(%Xh)", RS, IW, RD, IW2); W+=2; break;
409 case 7: DASM("invalid opcode [%08Xh] 1011", OP); break;
410 }
411 }
412
dasm_prefix_1100(dasm_state & st)413 static void dasm_prefix_1100(dasm_state &st)
414 {
415 const char *cond_table[16] = {
416 /* 0000 */ "",
417 /* 0001 */ "p",
418 /* 0010 */ "ls",
419 /* 0011 */ "hi",
420 /* 0100 */ "lt",
421 /* 0101 */ "ge",
422 /* 0110 */ "le",
423 /* 0111 */ "gt",
424 /* 1000 */ "c",
425 /* 1001 */ "nc",
426 /* 1010 */ "eq",
427 /* 1011 */ "ne",
428 /* 1100 */ "v",
429 /* 1101 */ "nv",
430 /* 1110 */ "n",
431 /* 1111 */ "nn"
432 };
433 unsigned cc = (OP >> 8) & 0xF;
434 if ((OP & 0xFF) == 0x0) {
435 DASM("jr%s %08x (IW)", cond_table[cc], WDISP);
436 W++;
437 } else if ((OP & 0xFF) == 0x80) {
438 DASM("ja%s %08x", cond_table[cc], IL);
439 W+=2;
440 } else {
441 DASM("jr%s %08x", cond_table[cc], BDISP);
442 }
443 }
444
dasm_prefix_1101(dasm_state & st)445 static void dasm_prefix_1101(dasm_state &st)
446 {
447 switch ((OP >> 8) & 0xF) {
448 case 0x0:
449 case 0x1: DASM("move *%s(%0x04x), %s, 0", RS, IW, RD); W++; break;
450 case 0x2:
451 case 0x3: DASM("move *%s(%0x04x), %s, 1", RS, IW, RD); W++; break;
452 case 0x4: DASM("move @%08Xh, %s, 0", IL, RD); W+=2; break;
453 case 0x5: DASM("exgf %s, 0", RD); break;
454 case 0x6: DASM("move @%08Xh, %s, 1", IL, RD); W+=2; break;
455 case 0x7: DASM("exgf %s, 1", RD); break;
456 case 0xF:
457 if (((OP >> 4) & 7) == 1) {
458 DASM("line %d", (OP >> 7) & 1);
459 break;
460 }
461 default:
462 DASM("invalid opcode [%04Xh] 1101", OP);
463 break;
464 }
465 }
466
dasm_prefix_1110(dasm_state & st)467 static void dasm_prefix_1110(dasm_state &st)
468 {
469 switch ((OP >> 9) & 7) {
470 case 0: DASM("addxy %s, %s", RS, RD); break;
471 case 1: DASM("subxy %s, %s", RS, RD); break;
472 case 2: DASM("cmpxy %s, %s", RS, RD); break;
473 case 3: DASM("cpw %s, %s", RS, RD); break;
474 case 4: DASM("cvxyl %s, %s", RS, RD); break;
475 case 5: DASM("invalid opcode [%04Xh] 1110", OP); break;
476 case 6: DASM("movx %s, %s", RS, RD); break;
477 case 7: DASM("movy %s, %s", RS, RD); break;
478 }
479 }
480
481
dasm_prefix_1111(dasm_state & st)482 static void dasm_prefix_1111(dasm_state &st)
483 {
484 switch ((st.opcode >> 9) & 7) {
485 case 0: DASM("pixt %s, *%s.xy", RS, RD); break;
486 case 1: DASM("pixt *%s.xy, %s", RS, RD); break;
487 case 2: DASM("pixt *%s.xy, *%s.xy", RS, RD); break;
488 case 3: DASM("drav %s, %s", RS, RD); break;
489 case 4: DASM("pixt %s, *%s", RS, RD); break;
490 case 5: DASM("pixt *%s, %s", RS, RD); break;
491 case 6: DASM("pixt *%s, *%s", RS, RD); break;
492 case 7: DASM("invalid opcode [%04Xh] 1111", OP); break;
493 }
494 }
495
new_dasm(dword pc,size_t * size)496 std::string new_dasm(dword pc, size_t *size)
497 {
498 dasm_state st;
499
500 st.pc = pc & ~0xF;
501 st.opcode = READ_WORD(pc);
502 st.iw = READ_WORD(pc + 16);
503 st.iw2 = READ_WORD(pc + 32);
504 st.il = READ_DWORD(pc + 16);
505 st.il2 = READ_DWORD(pc + 16 + 32);
506 st.words = 1;
507
508 switch ((OP >> 12) & 0xF) {
509 case 0x0: dasm_prefix_0000(st); break;
510 case 0x1: dasm_prefix_0001(st); break;
511 case 0x2: dasm_prefix_0010(st); break;
512 case 0x3: dasm_prefix_0011(st); break;
513 case 0x4: dasm_prefix_0100(st); break;
514 case 0x5: dasm_prefix_0101(st); break;
515 case 0x6: dasm_prefix_0110(st); break;
516 case 0x7: dasm_prefix_0111(st); break;
517 case 0x8: dasm_prefix_1000(st); break;
518 case 0x9: dasm_prefix_1001(st); break;
519 case 0xA: dasm_prefix_1010(st); break;
520 case 0xB: dasm_prefix_1011(st); break;
521 case 0xC: dasm_prefix_1100(st); break;
522 case 0xD: dasm_prefix_1101(st); break;
523 case 0xE: dasm_prefix_1110(st); break;
524 case 0xF: dasm_prefix_1111(st); break;
525 }
526
527 if (size)
528 *size = st.words * 16;
529
530 return std::string(st.buf);
531 }
532
533 }
534