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