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 #define READ_WORD(addr) tms::read_word(addr)
11 #define READ_DWORD(addr) (READ_WORD(addr) | (READ_WORD(addr + 16) << 16))
12 
13 #define BKW_DIR (opcode & (1 << 10))
14 #define OFFS    ((opcode >> 5) & 0x1F)
15 #define K       fw_lut[((opcode >> 5) & 0x1F)]
16 #define KN      ((~opcode >> 5) & 0x1F)
17 #define K2C     ((-K) & 0x1F)
18 #define M_BIT   (opcode & (1 << 9))
19 #define R_BIT   (opcode & 0x10)
20 #define RS      (((opcode >> 5) & 0xF) | R_BIT)
21 #define RD      ((opcode & 0xF) | R_BIT)
22 #define NF      (opcode & 0x1F)
23 #define RS_n    ((opcode >> 5) & 0xF)
24 #define RD_n    (opcode & 0xF)
25 
26 namespace tms
27 {
28 
29 const int dasm_buf_size = 128;
30 const int dasm_pc_size = 32;
31 
32 const char *reg_names[32] =
33 {
34     "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
35     "a8", "a9", "a10", "a11", "a12", "a13", "a14", "sp",
36     "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7",
37     "b8", "b9", "b10", "b11", "b12", "b13", "b14", "sp",
38 };
39 
dsjs_pc(dword pc,word opcode)40 static inline dword dsjs_pc(dword pc, word opcode)
41 {
42     int displace = OFFS * 16;
43     if (BKW_DIR)
44         displace = -displace;
45     return pc + displace;
46 }
47 
jr_pc(dword pc,word opcode)48 static inline dword jr_pc(dword pc, word opcode)
49 {
50     int displace = (opcode & 0xFF) * 16;
51     if (BKW_DIR)
52         displace = -displace;
53     return pc + displace;
54 }
55 
jr_cond(word opcode)56 static inline const char *jr_cond(word opcode)
57 {
58     const char *cond_table[16] = {
59         /* 0000 */ "",
60         /* 0001 */ "p",
61         /* 0010 */ "ls",
62         /* 0011 */ "hi",
63         /* 0100 */ "lt",
64         /* 0101 */ "ge",
65         /* 0110 */ "le",
66         /* 0111 */ "gt",
67         /* 1000 */ "c",
68         /* 1001 */ "nc",
69         /* 1010 */ "eq",
70         /* 1011 */ "ne",
71         /* 1100 */ "v",
72         /* 1101 */ "nv",
73         /* 1110 */ "n",
74         /* 1111 */ "nn"
75     };
76     return cond_table[(opcode >> 8) & 0xF];
77 }
78 
79 
reg_list(word opcode,word data)80 static const char *reg_list(word opcode, word data)
81 {
82     int inc = (opcode & 0x10) ? 16 : 0;
83     std::vector<std::string> regs;
84     regs.reserve(16);
85 
86 
87     for (int i = 0; i < 16; i++) {
88         if (data & 0x8000)
89             regs.push_back(reg_names[inc + i]);
90         data <<= 1;
91     }
92 
93 
94     std::string s;
95     s.reserve(100);
96     for (int i = 0; i < regs.size(); i++) {
97         s.append(regs[i]);
98         if (i != regs.size() - 1)
99             s.append(",");
100     }
101 
102     return s.c_str();
103 }
104 
reg_list_inv(word opcode,word data)105 static const char *reg_list_inv(word opcode, word data)
106 {
107     int inc = (opcode & 0x10) ? 16 : 0;
108     std::vector<std::string> regs;
109     regs.reserve(16);
110 
111 
112     for (int i = 0; i < 16; i++) {
113         if (data & 1)
114             regs.push_back(reg_names[inc + i]);
115         data >>= 1;
116     }
117 
118 
119     std::string s;
120     s.reserve(100);
121     for (int i = 0; i < regs.size(); i++) {
122         s.append(regs[i]);
123         if (i != regs.size() - 1)
124             s.append(",");
125     }
126 
127     return s.c_str();
128 }
129 
130 #define DASM(...)    snprintf(buf, dasm_buf_size, __VA_ARGS__)
131 
dasm(dword pc,size_t * szbits)132 std::string dasm(dword pc, size_t *szbits)
133 {
134     const int size = 128;
135     char buf[size];
136     char pcb[dasm_pc_size];
137 
138     word opcode = READ_WORD(pc);
139 
140     buf[0] = '\0';
141     pcb[0] = '\0';
142 
143     snprintf(pcb, dasm_pc_size, "%08X\t%04X\t", pc, opcode);
144     int fs = opcode & 0x1F;
145     int fe = (opcode & (1 << 5)) ? 1 : 0;
146     int f = (opcode & (1 << 9)) ? 1 : 0;
147     int rd = RD;
148     int rs = RS;
149     //int rfile = (opcode >> 5) & 1;
150 
151     int words = 1;
152 
153     if (!fs)
154         fs = 32;
155 
156     switch (opcode >> 12) {
157     case 0x00:
158         switch ((opcode >> 5) & 0x7F) {
159 
160         case 0x09: DASM("exgpc %s", reg_names[rd]); break;
161         case 0x0A: DASM("getpc %s", reg_names[rd]); break;
162         case 0x0B: DASM("jump %s", reg_names[rd]); break;
163         case 0x0F: DASM("pushst"); break;
164         case 0x0E: DASM("popst"); break;
165         case 0x1B: DASM("dint"); break;
166         case 0x6B: DASM("eint"); break;
167 
168         case 0x1F: DASM("not %s", reg_names[rd]); break;
169 
170         case 0x2F: DASM("movb %s, @%x", reg_names[rd], READ_DWORD(pc + 16)); words += 2; break;
171         case 0x3F: DASM("movb @%x, %s", READ_DWORD(pc + 16), reg_names[rd]); words += 2; break;
172 
173         case 0x2A:
174         case 0x2B:
175         case 0x3A:
176         case 0x3B: DASM("setf 0x%x, %d, %d", fs, fe, f); break;
177 
178         case 0x4D: DASM("mmfm %s, %s", reg_names[rd], reg_list_inv(opcode, READ_WORD(pc + 16))); words++; break;
179 
180         case 0x4E: DASM("movi 0x%04x, %s", READ_WORD(pc + 16), reg_names[rd]); words++; break;
181         case 0x4F: DASM("movi 0x%08x, %s", READ_DWORD(pc + 16), reg_names[rd]); words += 2; break;
182 
183         case 0x3C:
184         case 0x2C: DASM("move %s, @%x, %d", reg_names[rd], READ_DWORD(pc + 16), f); words += 2; break;
185 
186         case 0x3D:
187         case 0x2D: DASM("move @%x, %s, %d", READ_DWORD(pc + 16), reg_names[rd], f); words += 2; break;
188 
189         case 0x4B: DASM("rets 0x%x", NF); break;
190         case 0x4C: DASM("mmtm %s, %s", reg_names[rd], reg_list(opcode, READ_WORD(pc + 16))); words++; break;
191 
192         case 0x58: DASM("addi 0x%08x, %s", READ_WORD(pc + 16), reg_names[rd]); words++; break;
193         case 0x59: DASM("addi 0x%08x, %s", READ_DWORD(pc + 16), reg_names[rd]); words += 2; break;
194         case 0x5C: DASM("andi 0x%08x, %s", ~READ_DWORD(pc + 16), reg_names[rd]); words += 2; break;
195 
196         case 0x5F: DASM("subi 0x%08x, %s", ~(short)READ_WORD(pc + 16), reg_names[rd]); words++; break;
197         case 0x68: DASM("subi 0x%08x, %s", ~READ_DWORD(pc + 16), reg_names[rd]); words += 2; break;
198 
199         case 0x5A: DASM("cmpi 0x%08x, %s", ~(short)READ_WORD(pc + 16), reg_names[rd]); words++; break;
200         case 0x5B: DASM("cmpi 0x%08x, %s", ~READ_DWORD(pc + 16), reg_names[rd]); words += 2; break;
201 
202         case 0x69: {
203             switch (opcode & 0xFF) {
204             case 0x3F:
205                 DASM("callr @%x", pc + 32 + (short)READ_WORD(pc + 16) * 16); words++; break;
206             }
207         }
208         case 0x6A: {
209             switch (opcode & 0xFF) {
210             case 0x5F:
211                 DASM("calla @%x", READ_DWORD(pc + 16)); words += 2; break;
212             }
213             break;
214         }
215 
216         case 0x6C: DASM("dsj %s, @%x", reg_names[rd], pc + 32 + (short)READ_WORD(pc + 16) * 16); words++; break;
217         case 0x7D: DASM("pixblt b, xy"); break;
218 
219 
220         default:
221             DASM("[%04X] ??? [0000]", opcode);
222             break;
223         }
224         break;
225 
226     case 0x01:
227         switch ((opcode >> 10) & 3) {
228         case 0x03: DASM("btst 0x%x, %s", KN, reg_names[rd]); break;
229         case 0x02: DASM("movk 0x%x, %s", K, reg_names[rd]); break;
230         case 0x01: DASM("subk 0x%x, %s", K, reg_names[rd]); break;
231         case 0x00: DASM("addk 0x%x, %s", K, reg_names[rd]); break;
232         default:
233             DASM("[%04X] ??? [0001]", opcode);
234             break;
235         }
236         break;
237 
238     case 0x02:
239         switch ((opcode >> 10) & 3) {
240         case 0x01: DASM("sll 0x%x, %s", K, reg_names[rd]); break;
241         case 0x03: DASM("srl 0x%x, %s", K2C, reg_names[rd]); break;
242         default:
243             DASM("[%04X] ??? [0010]", opcode);
244             break;
245         }
246         break;
247 
248     case 0x03:
249         if (opcode & (1 << 11))
250             DASM("dsjs %s, @%x", reg_names[rd], dsjs_pc(pc + 16, opcode));
251         else {
252             DASM("[%04X] ??? [0011]", opcode);
253         }
254         break;
255     case 0x04:
256         switch ((opcode >> 9) & 7) {
257         case 0x0: DASM("add %s, %s", reg_names[rs], reg_names[rd]); break;
258         case 0x2: DASM("sub %s, %s", reg_names[rs], reg_names[rd]); break;
259         case 0x4: DASM("cmp %s, %s", reg_names[rs], reg_names[rd]); break;
260         case 0x6: DASM("move %s, %s", reg_names[rs], reg_names[rd]); break;
261         case 0x7: {
262             int rs_, rd_;
263             if (R_BIT) {
264                 rs_ = 16 + RS_n;
265                 rd_ = RD_n;
266             } else {
267                 rs_ = RS_n;
268                 rd_ = 16 + RD_n;
269             }
270             DASM("move %s, %s", reg_names[rs_], reg_names[rd_]);
271             break;
272         }
273 
274         default:
275             DASM("[%04X] ??? [0100]", opcode);
276             break;
277         }
278 
279         break;
280 
281     case 0x05:
282         switch ((opcode >> 9) & 7) {
283         case 0x00: DASM("and %s, %s", reg_names[rs], reg_names[rd]); break;
284         case 0x01: DASM("andn %s, %s", reg_names[rs], reg_names[rd]); break;
285         case 0x02: DASM("or %s, %s", reg_names[rs], reg_names[rd]); break;
286         case 0x03:
287             if (rs == rd)
288                 DASM("clr %s", reg_names[rs]);
289             else
290                 DASM("xor %s, %s", reg_names[rs], reg_names[rd]);
291             break;
292         case 0x04: DASM("divs %s, %s", reg_names[rs], reg_names[rd]); break;
293         case 0x05: DASM("divu %s, %s", reg_names[rs], reg_names[rd]); break;
294         case 0x06: DASM("mpys %s, %s", reg_names[rs], reg_names[rd]); break;
295         case 0x07: DASM("mpyu %s, %s", reg_names[rs], reg_names[rd]); break;
296         default:
297             DASM("[%04X] ??? [0101]", opcode);
298         }
299 
300         break;
301 
302     case 0x06:
303         switch ((opcode >> 9) & 7) {
304         case 0x05: DASM("lmo %s, %s", reg_names[rs], reg_names[rd]); break;
305         case 0x07: DASM("modu %s, %s", reg_names[rs], reg_names[rd]); break;
306         default:
307             DASM("[%04X] ??? [0110]", opcode);
308             break;
309         }
310         break;
311 
312 
313     case 0x08:
314         switch ((opcode >> 9) & 7) {
315         case 0x7: DASM("movb *%s, %s", reg_names[rs], reg_names[rd]); break;
316         case 0x6: DASM("movb %s, *%s", reg_names[rs], reg_names[rd]); break;
317         case 0x2: DASM("move *%s, %s, 0", reg_names[rs], reg_names[rd]); break;
318         case 0x3: DASM("move *%s, %s, 1", reg_names[rs], reg_names[rd]); break;
319         case 0x0: DASM("move %s, *%s, 0", reg_names[rs], reg_names[rd]); break;
320         case 0x1: DASM("move %s, *%s, 1", reg_names[rs], reg_names[rd]); break;
321 
322         default:
323             DASM("[%04X] ??? [1000]", opcode);
324             break;
325         }
326 
327         break;
328 
329 
330 
331     case 0x09:
332         switch ((opcode >> 9) & 7) {
333         case 0x00: DASM("move %s, *%s+, 0", reg_names[rs], reg_names[rd]); break;
334         case 0x01: DASM("move %s, *%s+, 1", reg_names[rs], reg_names[rd]); break;
335         case 0x02: DASM("move *%s+, %s, 0", reg_names[rs], reg_names[rd]); break;
336         case 0x03: DASM("move *%s+, %s, 1", reg_names[rs], reg_names[rd]); break;
337         case 0x04: DASM("move *%s+, *%s+, 0", reg_names[rs], reg_names[rd]); break;
338         case 0x05: DASM("move *%s+, *%s+, 1", reg_names[rs], reg_names[rd]); break;
339         default:
340             DASM("[%04X] ??? [1001]", opcode);
341             break;
342         }
343         break;
344 
345     case 0x0A:
346         switch ((opcode >> 9) & 7) {
347         case 0x00: DASM("move %s, -*%s, 0", reg_names[rs], reg_names[rd]); break;
348         case 0x01: DASM("move %s, -*%s, 1", reg_names[rs], reg_names[rd]); break;
349         case 0x02: DASM("move -%s, *%s, 0", reg_names[rs], reg_names[rd]); break;
350         case 0x03: DASM("move -%s, *%s, 1", reg_names[rs], reg_names[rd]); break;
351         case 0x04: DASM("move -%s, -*%s, 0", reg_names[rs], reg_names[rd]); break;
352         case 0x05: DASM("move -%s, -*%s, 1", reg_names[rs], reg_names[rd]); break;
353         case 0x06: DASM("movb %s, *%s(%x), 1", reg_names[rs], reg_names[rd],READ_WORD(pc+16)); words++; break;
354         case 0x07: DASM("movb %s(%x), *%s, 1", reg_names[rs], READ_WORD(pc+16),reg_names[rd]); words++; break;
355         default:
356             DASM("[%04X] ??? [1010]", opcode);
357             break;
358         }
359         break;
360 
361     case 0x0B:
362         switch ((opcode >> 9) & 7) {
363         case 0x00: DASM("move %s, *%s(%x), 0", reg_names[rs], reg_names[rd],READ_WORD(pc+16)); words++; break;
364         case 0x01: DASM("move %s, *%s(%x), 1", reg_names[rs], reg_names[rd],READ_WORD(pc+16)); words++; break;
365         case 0x02: DASM("move *%s(%x), %s, 0", reg_names[rs], READ_WORD(pc+16), reg_names[rd]); words++; break;
366         case 0x03: DASM("move *%s(%x), %s, 1", reg_names[rs], READ_WORD(pc+16), reg_names[rd]); words++; break;
367         case 0x04: DASM("move *%s(%x), *%s(%x), 0", reg_names[rs], READ_WORD(pc+16),reg_names[rd],READ_WORD(pc+32)); words+=2; break;
368         case 0x05: DASM("move *%s(%x), *%s(%x), 1", reg_names[rs], READ_WORD(pc+16),reg_names[rd],READ_WORD(pc+32)); words+=2; break;
369         default:
370             DASM("[%04X] ??? [1011]", opcode);
371             break;
372         }
373         break;
374 
375 
376     case 0x0C:
377         if (opcode & 0xFF) {
378             if ((opcode & 0xFF) == 0x80) { // JA addr
379                 DASM("ja%s @%x", jr_cond(opcode), READ_DWORD(pc + 16));
380                 words += 2;
381                 break;
382             }
383             // JR shor addr
384             DASM("jr%s @%x", jr_cond(opcode), pc + 16 + ((int8_t)(opcode & 0xFF)) * 16);
385         } else {
386             // JR rel cond
387             DASM("jr%s @%x", jr_cond(opcode), pc + 32 + (short)READ_WORD(pc + 16) * 16);
388             words++;
389         }
390         break;
391 
392 
393     case 0x0E:
394         switch ((opcode >> 9) & 7) {
395         case 0x6: DASM("movx %s, %s", reg_names[rs], reg_names[rd]); break;
396         case 0x7: DASM("movy %s, %s", reg_names[rs], reg_names[rd]); break;
397         default:
398             DASM("[%04X] ??? [1110]", opcode);
399             break;
400         }
401 
402         break;
403 
404     default:
405         DASM("[%04X] ???", opcode);
406         break;
407     }
408 
409     if (szbits)
410         *szbits = words * 16;
411 
412     return std::string(buf);
413 }
414 
415 }
416 
417