1 // license:BSD-3-Clause
2 // copyright-holders:AJR
3 /***************************************************************************
4
5 National Semiconductor CompactRISC CR16B disassembler
6
7 Core architecture versions supported by this disassembler:
8 * CR16A: 17-bit PC, 18-bit address space
9 * CR16B: 21-bit PC with large memory model, enhanced instruction set
10
11 CR16C has a 24-bit PC and expands the instruction set still further.
12 Its instruction encoding is entirely different and is therefore not
13 supported here.
14
15 It should be noted that the PC is guaranteed to be always aligned to
16 even addresses. To this end, whenever the PC is stored in or loaded
17 from a register or register pair or a stack, the bits are shifted
18 right or left by one.
19
20 ***************************************************************************/
21
22 #include "emu.h"
23 #include "util/disasmintf.h"
24 #include "cr16bdasm.h"
25
26 #include "util/strformat.h"
27
28 using osd::u32;
29 using util::BIT;
30 using offs_t = u32;
31
cr16b_disassembler(cr16_arch arch)32 cr16b_disassembler::cr16b_disassembler(cr16_arch arch)
33 : util::disasm_interface()
34 , m_arch(arch)
35 {
36 }
37
cr16a_disassembler()38 cr16a_disassembler::cr16a_disassembler()
39 : cr16b_disassembler(cr16_arch::CR16A)
40 {
41 }
42
cr16b_disassembler()43 cr16b_disassembler::cr16b_disassembler()
44 : cr16b_disassembler(cr16_arch::CR16B)
45 {
46 }
47
opcode_alignment() const48 u32 cr16b_disassembler::opcode_alignment() const
49 {
50 return 2;
51 }
52
53 // Condition codes
54 const char *const cr16b_disassembler::s_cc[14] =
55 {
56 "eq", "ne",
57 "cs", "cc",
58 "hi", "ls",
59 "gt", "le",
60 "fs", "fc",
61 "lo", "hs",
62 "lt", "ge"
63 };
64
65
format_reg(std::ostream & stream,u8 reg)66 void cr16b_disassembler::format_reg(std::ostream &stream, u8 reg)
67 {
68 if (reg == 15)
69 stream << "sp";
70 else if (reg == 14)
71 stream << "ra";
72 else if (reg == 13 && m_arch != cr16_arch::CR16A)
73 stream << "era"; // R13 in SMM
74 else
75 util::stream_format(stream, "r%d", reg);
76 }
77
format_rpair(std::ostream & stream,u8 reg)78 void cr16b_disassembler::format_rpair(std::ostream &stream, u8 reg)
79 {
80 if (reg == 13 && m_arch != cr16_arch::CR16A)
81 stream << "(ra,era)";
82 else
83 util::stream_format(stream, "(r%d,r%d)", reg + 1, reg);
84 }
85
format_rproc(std::ostream & stream,u8 reg)86 void cr16a_disassembler::format_rproc(std::ostream &stream, u8 reg)
87 {
88 switch (reg)
89 {
90 case 1:
91 stream << "psr";
92 break;
93
94 case 3:
95 stream << "intbase";
96 break;
97
98 case 11:
99 stream << "isp";
100 break;
101
102 default:
103 stream << "res";
104 break;
105 }
106 }
107
format_rproc(std::ostream & stream,u8 reg)108 void cr16b_disassembler::format_rproc(std::ostream &stream, u8 reg)
109 {
110 switch (reg)
111 {
112 case 1:
113 stream << "psr";
114 break;
115
116 case 3:
117 stream << "intbasel";
118 break;
119
120 case 4:
121 stream << "intbaseh";
122 break;
123
124 case 5:
125 stream << "cfg";
126 break;
127
128 case 7:
129 stream << "dsr";
130 break;
131
132 case 9:
133 stream << "dcr";
134 break;
135
136 case 11:
137 stream << "isp";
138 break;
139
140 case 13:
141 stream << "carl";
142 break;
143
144 case 14:
145 stream << "carh";
146 break;
147
148 default:
149 stream << "res";
150 break;
151 }
152 }
153
format_short_imm(std::ostream & stream,u8 imm)154 void cr16b_disassembler::format_short_imm(std::ostream &stream, u8 imm)
155 {
156 // 5-bit short immediate value (0 to 15, -16, -14 to -1)
157 if (imm == 0)
158 stream << "$0";
159 else if (imm >= 0x10)
160 util::stream_format(stream, "$-0x%X", 0x10 - (imm & 0x0f));
161 else
162 util::stream_format(stream, "$0x%X", imm);
163 }
164
format_short_imm_unsigned(std::ostream & stream,u8 imm,bool i)165 void cr16b_disassembler::format_short_imm_unsigned(std::ostream &stream, u8 imm, bool i)
166 {
167 if (imm == 0)
168 stream << "$0";
169 else if (i)
170 util::stream_format(stream, "$0x%04X", (imm >= 0x10) ? 0xfff0 | (imm & 0x0f) : imm);
171 else
172 util::stream_format(stream, "$0x%02X", (imm >= 0x10) ? 0xf0 | (imm & 0x0f) : imm);
173 }
174
format_short_imm_decimal(std::ostream & stream,u8 imm)175 void cr16b_disassembler::format_short_imm_decimal(std::ostream &stream, u8 imm)
176 {
177 if (imm >= 0x10)
178 util::stream_format(stream, "$-%d", 0x10 - (imm & 0x0f));
179 else
180 util::stream_format(stream, "$%d", imm);
181 }
182
format_medium_imm(std::ostream & stream,u16 imm)183 void cr16b_disassembler::format_medium_imm(std::ostream &stream, u16 imm)
184 {
185 if (imm >= 0x8000)
186 util::stream_format(stream, "$-0x%X", 0x10000 - imm);
187 else
188 util::stream_format(stream, "$0x%X", imm);
189 }
190
format_medium_imm_unsigned(std::ostream & stream,u16 imm,bool i)191 void cr16b_disassembler::format_medium_imm_unsigned(std::ostream &stream, u16 imm, bool i)
192 {
193 if (i)
194 util::stream_format(stream, "$0x%04X", imm);
195 else
196 util::stream_format(stream, "$0x%02X", imm & 0xff);
197 }
198
format_medium_imm_decimal(std::ostream & stream,u16 imm)199 void cr16b_disassembler::format_medium_imm_decimal(std::ostream &stream, u16 imm)
200 {
201 util::stream_format(stream, "$%d", s16(imm));
202 }
203
format_imm21(std::ostream & stream,u32 imm)204 void cr16b_disassembler::format_imm21(std::ostream &stream, u32 imm)
205 {
206 util::stream_format(stream, "$0x%06X", imm);
207 }
208
format_disp5(std::ostream & stream,u8 disp)209 void cr16b_disassembler::format_disp5(std::ostream &stream, u8 disp)
210 {
211 // 5-bit short displacement (0 to 15, 16 to 30 even)
212 if (disp == 0)
213 stream << "0";
214 else
215 util::stream_format(stream, "0x%X", disp);
216 }
217
format_disp16(std::ostream & stream,u16 disp)218 void cr16b_disassembler::format_disp16(std::ostream &stream, u16 disp)
219 {
220 // 16-bit displacement (0 to 64K-1)
221 util::stream_format(stream, "0x%X", disp);
222 }
223
format_disp18(std::ostream & stream,u32 disp)224 void cr16b_disassembler::format_disp18(std::ostream &stream, u32 disp)
225 {
226 // 18-bit medium displacement (-128K to 128K-1 or 0 to 256K-1, result truncated to 18 bits)
227 if (disp == 0)
228 stream << "0";
229 else if (disp >= 0x20000)
230 util::stream_format(stream, "-0x%X", 0x40000 - disp);
231 else
232 util::stream_format(stream, "0x%X", disp);
233 }
234
format_abs18(std::ostream & stream,u32 addr)235 void cr16b_disassembler::format_abs18(std::ostream &stream, u32 addr)
236 {
237 // 18-bit absolute (any memory location within first 256K)
238 util::stream_format(stream, "0x%05X", addr);
239 }
240
format_pc_disp5(std::ostream & stream,offs_t pc,u8 disp)241 void cr16b_disassembler::format_pc_disp5(std::ostream &stream, offs_t pc, u8 disp)
242 {
243 if (m_arch == cr16_arch::CR16A)
244 util::stream_format(stream, "0x%05X", (disp >= 0x10 ? pc + 0x20 - disp : pc + disp) & 0x1ffff); // SMM
245 else
246 util::stream_format(stream, "0x%06X", (disp >= 0x10 ? pc + 0x20 - disp : pc + disp) & 0x1fffff); // LMM
247 }
248
format_pc_disp9(std::ostream & stream,offs_t pc,u16 disp)249 void cr16b_disassembler::format_pc_disp9(std::ostream &stream, offs_t pc, u16 disp)
250 {
251 if (m_arch == cr16_arch::CR16A)
252 util::stream_format(stream, "0x%05X", (disp >= 0x100 ? pc + 0x200 - disp : pc + disp) & 0x1ffff); // SMM
253 else
254 util::stream_format(stream, "0x%06X", (disp >= 0x100 ? pc + 0x200 - disp : pc + disp) & 0x1fffff); // LMM
255 }
256
format_pc_disp17(std::ostream & stream,offs_t pc,u32 disp)257 void cr16b_disassembler::format_pc_disp17(std::ostream &stream, offs_t pc, u32 disp)
258 {
259 util::stream_format(stream, "0x%05X", (disp >= 0x10000 ? pc + 0x20000 - disp : pc + disp) & 0x1ffff);
260 }
261
format_pc_disp21(std::ostream & stream,offs_t pc,u32 disp)262 void cr16b_disassembler::format_pc_disp21(std::ostream &stream, offs_t pc, u32 disp)
263 {
264 util::stream_format(stream, "0x%06X", (pc + ((disp & 0x0ffffe) | (disp & 0x000001) << 20)) & 0x1fffff);
265 }
266
format_excp_vector(std::ostream & stream,u8 vec)267 void cr16b_disassembler::format_excp_vector(std::ostream &stream, u8 vec)
268 {
269 switch (vec)
270 {
271 case 0x05: // Supervisor call
272 stream << "svc";
273 break;
274
275 case 0x06: // Division by zero
276 stream << "dvz";
277 break;
278
279 case 0x07: // Flag
280 stream << "flg";
281 break;
282
283 case 0x08: // Breakpoint
284 stream << "bpt";
285 break;
286
287 case 0x0a: // Undefined instruction
288 stream << "und";
289 break;
290
291 case 0x0e: // Debug
292 stream << (m_arch != cr16_arch::CR16A ? "dbg" : "und ; reserved");
293 break;
294
295 default:
296 stream << "und ; reserved";
297 break;
298 }
299 }
300
disassemble(std::ostream & stream,offs_t pc,const cr16b_disassembler::data_buffer & opcodes,const cr16b_disassembler::data_buffer & params)301 offs_t cr16b_disassembler::disassemble(std::ostream &stream, offs_t pc, const cr16b_disassembler::data_buffer &opcodes, const cr16b_disassembler::data_buffer ¶ms)
302 {
303 u16 opcode = opcodes.r16(pc);
304
305 if (BIT(opcode, 15))
306 {
307 // Load and store group (excluding LOADM, STORM)
308 if (BIT(opcode, 14))
309 {
310 util::stream_format(stream, "stor%c ", BIT(opcode, 13) ? 'w' : 'b');
311 format_reg(stream, (opcode & 0x01e0) >> 5);
312 stream << ", ";
313 }
314 else
315 util::stream_format(stream, "load%c ", BIT(opcode, 13) ? 'w' : 'b');
316
317 switch (opcode & 0x1801)
318 {
319 case 0x1001:
320 format_disp18(stream, u32(opcode & 0x0600) << 7 | opcodes.r16(pc + 2));
321 stream << "(";
322 format_reg(stream, (opcode & 0x001e) >> 1);
323 stream << ")";
324 if (!BIT(opcode, 14))
325 {
326 stream << ", ";
327 format_reg(stream, (opcode & 0x01e0) >> 5);
328 }
329 return 4 | SUPPORTED;
330
331 case 0x1801:
332 if ((opcode & 0x001e) == 0x001e)
333 format_abs18(stream, u32(opcode & 0x0600) << 7 | opcodes.r16(pc + 2));
334 else
335 {
336 format_disp18(stream, u32(opcode & 0x0600) << 7 | opcodes.r16(pc + 2));
337 format_rpair(stream, (opcode & 0x001e) >> 1);
338 }
339 if (!BIT(opcode, 14))
340 {
341 stream << ", ";
342 format_reg(stream, (opcode & 0x01e0) >> 5);
343 }
344 return 4 | SUPPORTED;
345
346 default:
347 format_disp5(stream, (opcode & 0x1e00) >> 8 | (opcode & 0x0001));
348 stream << "(";
349 format_reg(stream, (opcode & 0x001e) >> 1);
350 stream << ")";
351 if (!BIT(opcode, 14))
352 {
353 stream << ", ";
354 format_reg(stream, (opcode & 0x01e0) >> 5);
355 }
356 return 2 | SUPPORTED;
357 }
358 }
359 else switch (opcode & 0x7e01)
360 {
361 case 0x0000: case 0x0001: case 0x2000: case 0x2001:
362 util::stream_format(stream, "add%c ", BIT(opcode, 13) ? 'w' : 'b');
363 if ((opcode & 0x001f) == 0x0011)
364 {
365 format_medium_imm(stream, opcodes.r16(pc + 2));
366 stream << ", ";
367 format_reg(stream, (opcode & 0x01e0) >> 5);
368 return 4 | SUPPORTED;
369 }
370 else
371 {
372 format_short_imm(stream, opcode & 0x001f);
373 stream << ", ";
374 format_reg(stream, (opcode & 0x01e0) >> 5);
375 return 2 | SUPPORTED;
376 }
377
378 case 0x0200: case 0x0201: case 0x2200: case 0x2201:
379 if (opcode == 0x0200) // NOP = ADDU $0, R0
380 stream << "nop";
381 else
382 {
383 util::stream_format(stream, "addu%c ", BIT(opcode, 13) ? 'w' : 'b');
384 if ((opcode & 0x001f) == 0x0011)
385 {
386 format_medium_imm(stream, opcodes.r16(pc + 2));
387 stream << ", ";
388 format_reg(stream, (opcode & 0x01e0) >> 5);
389 return 4 | SUPPORTED;
390 }
391 else
392 {
393 format_short_imm(stream, opcode & 0x001f);
394 stream << ", ";
395 format_reg(stream, (opcode & 0x01e0) >> 5);
396 return 2 | SUPPORTED;
397 }
398 }
399 return 2 | SUPPORTED;
400
401 case 0x0400: case 0x0401: case 0x2400: case 0x2401:
402 case 0x4401: case 0x6401:
403 // Bit manipulation and store immediate (memory operand)
404 if (m_arch == cr16_arch::CR16A)
405 {
406 stream << "res";
407 return 2 | SUPPORTED;
408 }
409 switch (opcode & 0x00c0)
410 {
411 case 0x0000:
412 util::stream_format(stream, "cbit%c $%d", BIT(opcode, 13) ? 'w' : 'b', (opcode & 0x001e) >> 1);
413 break;
414
415 case 0x0040:
416 util::stream_format(stream, "sbit%c $%d", BIT(opcode, 13) ? 'w' : 'b', (opcode & 0x001e) >> 1);
417 break;
418
419 case 0x0080:
420 util::stream_format(stream, "tbit%c $%d", BIT(opcode, 13) ? 'w' : 'b', (opcode & 0x001e) >> 1);
421 break;
422
423 case 0x00c0:
424 util::stream_format(stream, "stor%c ", BIT(opcode, 13) ? 'w' : 'b');
425 format_short_imm(stream, (opcode & 0x001e) >> 1); // unsigned 4-bit value
426 break;
427 }
428 if (BIT(opcode, 14))
429 {
430 stream << ", 0(";
431 format_reg(stream, (opcode & 0x0120) >> 5);
432 stream << ")";
433 return 2 | SUPPORTED;
434 }
435 else
436 {
437 stream << ", ";
438 if (BIT(opcode, 0))
439 {
440 format_disp16(stream, opcodes.r16(pc + 2));
441 stream << "(";
442 format_reg(stream, (opcode & 0x0120) >> 5);
443 stream << ")";
444 }
445 else
446 format_abs18(stream, u32(opcode & 0x0100) << 9 | u32(opcode & 0x0020) << 11 | opcodes.r16(pc + 2));
447 return 4 | SUPPORTED;
448 }
449
450 case 0x0600: case 0x0601: case 0x2600: case 0x2601:
451 util::stream_format(stream, "mul%c ", BIT(opcode, 13) ? 'w' : 'b');
452 if ((opcode & 0x001f) == 0x0011)
453 {
454 format_medium_imm(stream, opcodes.r16(pc + 2));
455 stream << ", ";
456 format_reg(stream, (opcode & 0x01e0) >> 5);
457 return 4 | SUPPORTED;
458 }
459 else
460 {
461 format_short_imm(stream, opcode & 0x001f);
462 stream << ", ";
463 format_reg(stream, (opcode & 0x01e0) >> 5);
464 return 2 | SUPPORTED;
465 }
466
467 case 0x0800: case 0x0801: case 0x2800: case 0x2801:
468 util::stream_format(stream, "ashu%c ", BIT(opcode, 13) ? 'w' : 'b');
469 if ((opcode & 0x001f) == 0x0011)
470 {
471 format_medium_imm_decimal(stream, opcodes.r16(pc + 2));
472 stream << ", ";
473 format_reg(stream, (opcode & 0x01e0) >> 5);
474 return 4 | SUPPORTED;
475 }
476 else
477 {
478 format_short_imm_decimal(stream, opcode & 0x001f);
479 stream << ", ";
480 format_reg(stream, (opcode & 0x01e0) >> 5);
481 return 2 | SUPPORTED;
482 }
483
484 case 0x0a00: case 0x0a01: case 0x2a00: case 0x2a01:
485 util::stream_format(stream, "lsh%c ", BIT(opcode, 13) ? 'w' : 'b');
486 if ((opcode & 0x001f) == 0x0011)
487 {
488 format_medium_imm_decimal(stream, opcodes.r16(pc + 2));
489 stream << ", ";
490 format_reg(stream, (opcode & 0x01e0) >> 5);
491 return 4 | SUPPORTED;
492 }
493 else
494 {
495 format_short_imm_decimal(stream, opcode & 0x001f);
496 stream << ", ";
497 format_reg(stream, (opcode & 0x01e0) >> 5);
498 return 2 | SUPPORTED;
499 }
500
501 case 0x0c00: case 0x0c01: case 0x2c00: case 0x2c01:
502 util::stream_format(stream, "xor%c ", BIT(opcode, 13) ? 'w' : 'b');
503 if ((opcode & 0x001f) == 0x0011)
504 {
505 format_medium_imm_unsigned(stream, opcodes.r16(pc + 2), BIT(opcode, 13));
506 stream << ", ";
507 format_reg(stream, (opcode & 0x01e0) >> 5);
508 return 4 | SUPPORTED;
509 }
510 else
511 {
512 format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13));
513 stream << ", ";
514 format_reg(stream, (opcode & 0x01e0) >> 5);
515 return 2 | SUPPORTED;
516 }
517
518 case 0x0e00: case 0x0e01: case 0x2e00: case 0x2e01:
519 util::stream_format(stream, "cmp%c ", BIT(opcode, 13) ? 'w' : 'b');
520 if ((opcode & 0x001f) == 0x0011)
521 {
522 format_medium_imm(stream, opcodes.r16(pc + 2));
523 stream << ", ";
524 format_reg(stream, (opcode & 0x01e0) >> 5);
525 return 4 | SUPPORTED;
526 }
527 else
528 {
529 format_short_imm(stream, opcode & 0x001f);
530 stream << ", ";
531 format_reg(stream, (opcode & 0x01e0) >> 5);
532 return 2 | SUPPORTED;
533 }
534
535 case 0x1000: case 0x1001: case 0x3000: case 0x3001:
536 util::stream_format(stream, "and%c ", BIT(opcode, 13) ? 'w' : 'b');
537 if ((opcode & 0x001f) == 0x0011)
538 {
539 format_medium_imm_unsigned(stream, opcodes.r16(pc + 2), BIT(opcode, 13));
540 stream << ", ";
541 format_reg(stream, (opcode & 0x01e0) >> 5);
542 return 4 | SUPPORTED;
543 }
544 else
545 {
546 format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13));
547 stream << ", ";
548 format_reg(stream, (opcode & 0x01e0) >> 5);
549 return 2 | SUPPORTED;
550 }
551
552 case 0x1200: case 0x1201: case 0x3200: case 0x3201:
553 util::stream_format(stream, "addc%c ", BIT(opcode, 13) ? 'w' : 'b');
554 if ((opcode & 0x001f) == 0x0011)
555 {
556 format_medium_imm(stream, opcodes.r16(pc + 2));
557 stream << ", ";
558 format_reg(stream, (opcode & 0x01e0) >> 5);
559 return 4 | SUPPORTED;
560 }
561 else
562 {
563 format_short_imm(stream, opcode & 0x001f);
564 stream << ", ";
565 format_reg(stream, (opcode & 0x01e0) >> 5);
566 return 2 | SUPPORTED;
567 }
568
569 case 0x1400:
570 // Conditional or unconditional branch to small address
571 if ((opcode & 0x000e) == 0x000e || (opcode & 0x01e0) != 0x01e0)
572 {
573 if ((opcode & 0x01e0) == 0x01c0)
574 stream << "br ";
575 else
576 util::stream_format(stream, "b%s ", s_cc[(opcode & 0x01e0) >> 5]);
577 format_pc_disp17(stream, pc, u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2));
578 return 4 | SUPPORTED;
579 }
580 else
581 {
582 stream << "res";
583 return 2 | SUPPORTED;
584 }
585
586 case 0x1401: case 0x3401:
587 // Compare and branch group
588 if (m_arch == cr16_arch::CR16A)
589 stream << "res";
590 else
591 {
592 util::stream_format(stream, "b%s%c%c ", BIT(opcode, 7) ? "ne" : "eq", BIT(opcode, 6) ? '1' : '0', BIT(opcode, 13) ? 'w' : 'b');
593 format_reg(stream, (opcode & 0x0120) >> 5);
594 stream << ", ";
595 format_pc_disp5(stream, pc, opcode & 0x001e);
596 }
597 return 2 | SUPPORTED;
598
599 case 0x1600:
600 // Jump and link to large address
601 if (m_arch == cr16_arch::CR16A)
602 stream << "res";
603 else
604 {
605 stream << "jal ";
606 format_rpair(stream, (opcode & 0x01e0) >> 5);
607 stream << ", ";
608 format_rpair(stream, (opcode & 0x001e) >> 1);
609 }
610 return 2 | SUPPORTED;
611
612 case 0x1601:
613 if ((opcode & 0x01e0) != 0x01e0 && m_arch != cr16_arch::CR16A)
614 {
615 if ((opcode & 0x01e0) == 0x01c0)
616 stream << "jump ";
617 else
618 util::stream_format(stream, "j%s ", s_cc[(opcode & 0x01e0) >> 5]);
619 format_rpair(stream, (opcode & 0x001e) >> 1);
620 return 2 | (opcode == 0x17db ? STEP_OUT : 0) | SUPPORTED;
621 }
622 else
623 {
624 stream << "res";
625 return 2 | SUPPORTED;
626 }
627
628 case 0x1800: case 0x1801: case 0x3800: case 0x3801:
629 util::stream_format(stream, "mov%c ", BIT(opcode, 13) ? 'w' : 'b');
630 if ((opcode & 0x001f) == 0x0011)
631 {
632 format_medium_imm_unsigned(stream, opcodes.r16(pc + 2), BIT(opcode, 13));
633 stream << ", ";
634 format_reg(stream, (opcode & 0x01e0) >> 5);
635 return 4 | SUPPORTED;
636 }
637 else
638 {
639 format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13));
640 stream << ", ";
641 format_reg(stream, (opcode & 0x01e0) >> 5);
642 return 2 | SUPPORTED;
643 }
644
645 case 0x1a00: case 0x1a01: case 0x3a00: case 0x3a01:
646 util::stream_format(stream, "subc%c ", BIT(opcode, 13) ? 'w' : 'b');
647 if ((opcode & 0x001f) == 0x0011)
648 {
649 format_medium_imm(stream, opcodes.r16(pc + 2));
650 stream << ", ";
651 format_reg(stream, (opcode & 0x01e0) >> 5);
652 return 4 | SUPPORTED;
653 }
654 else
655 {
656 format_short_imm(stream, opcode & 0x001f);
657 stream << ", ";
658 format_reg(stream, (opcode & 0x01e0) >> 5);
659 return 2 | SUPPORTED;
660 }
661
662 case 0x1c00: case 0x1c01: case 0x3c00: case 0x3c01:
663 util::stream_format(stream, "or%c ", BIT(opcode, 13) ? 'w' : 'b');
664 if ((opcode & 0x001f) == 0x0011)
665 {
666 format_medium_imm_unsigned(stream, opcodes.r16(pc + 2), BIT(opcode, 13));
667 stream << ", ";
668 format_reg(stream, (opcode & 0x01e0) >> 5);
669 return 4 | SUPPORTED;
670 }
671 else
672 {
673 format_short_imm_unsigned(stream, opcode & 0x001f, BIT(opcode, 13));
674 stream << ", ";
675 format_reg(stream, (opcode & 0x01e0) >> 5);
676 return 2 | SUPPORTED;
677 }
678
679 case 0x1e00: case 0x1e01: case 0x3e00: case 0x3e01:
680 util::stream_format(stream, "sub%c ", BIT(opcode, 13) ? 'w' : 'b');
681 if ((opcode & 0x001f) == 0x0011)
682 {
683 format_medium_imm(stream, opcodes.r16(pc + 2));
684 stream << ", ";
685 format_reg(stream, (opcode & 0x01e0) >> 5);
686 return 4 | SUPPORTED;
687 }
688 else
689 {
690 format_short_imm(stream, opcode & 0x001f);
691 stream << ", ";
692 format_reg(stream, (opcode & 0x01e0) >> 5);
693 return 2 | SUPPORTED;
694 }
695
696 case 0x3400:
697 // Branch and link to small address
698 if ((opcode & 0x000e) == 0x000e)
699 {
700 stream << "bal ";
701 format_reg(stream, (opcode & 0x01e0) >> 5);
702 stream << ", ";
703 format_pc_disp17(stream, pc, u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2));
704 return 4 | STEP_OVER | SUPPORTED;
705 }
706 else
707 {
708 stream << "res";
709 return 2 | SUPPORTED;
710 }
711
712 case 0x3600: case 0x3601:
713 // TBIT imm, reg only exists as a word operation
714 stream << "tbit ";
715 if ((opcode & 0x001f) == 0x0011)
716 {
717 format_medium_imm_decimal(stream, opcodes.r16(pc + 2));
718 stream << ", ";
719 format_reg(stream, (opcode & 0x01e0) >> 5);
720 return 4 | SUPPORTED;
721 }
722 else
723 {
724 format_short_imm_decimal(stream, opcode & 0x001f);
725 stream << ", ";
726 format_reg(stream, (opcode & 0x01e0) >> 5);
727 return 2 | SUPPORTED;
728 }
729
730 case 0x4000: case 0x4200: case 0x4400: case 0x4600:
731 case 0x4800: case 0x4a00: case 0x4c00: case 0x4e00:
732 case 0x5000: case 0x5200: case 0x5400: case 0x5600:
733 case 0x5800: case 0x5a00: case 0x5c00: case 0x5e00:
734 // Conditional or unconditional branch with 9-bit displacement
735 if ((opcode & 0x01e0) != 0x01e0)
736 {
737 if ((opcode & 0x01e0) == 0x01c0)
738 stream << "br ";
739 else
740 util::stream_format(stream, "b%s ", s_cc[(opcode & 0x01e0) >> 5]);
741 format_pc_disp9(stream, pc, (opcode & 0x1e00) >> 4 | (opcode & 0x001e));
742 }
743 else
744 stream << "res";
745 return 2 | SUPPORTED;
746
747 case 0x4001: case 0x6001:
748 util::stream_format(stream, "add%c ", BIT(opcode, 13) ? 'w' : 'b');
749 format_reg(stream, (opcode & 0x001e) >> 1);
750 stream << ", ";
751 format_reg(stream, (opcode & 0x01e0) >> 5);
752 return 2 | SUPPORTED;
753
754 case 0x4201: case 0x6201:
755 util::stream_format(stream, "addu%c ", BIT(opcode, 13) ? 'w' : 'b');
756 format_reg(stream, (opcode & 0x001e) >> 1);
757 stream << ", ";
758 format_reg(stream, (opcode & 0x01e0) >> 5);
759 return 2 | SUPPORTED;
760
761 case 0x4601: case 0x6601:
762 util::stream_format(stream, "mul%c ", BIT(opcode, 13) ? 'w' : 'b');
763 format_reg(stream, (opcode & 0x001e) >> 1);
764 stream << ", ";
765 format_reg(stream, (opcode & 0x01e0) >> 5);
766 return 2 | SUPPORTED;
767
768 case 0x4801: case 0x6801:
769 util::stream_format(stream, "ashu%c ", BIT(opcode, 13) ? 'w' : 'b');
770 format_reg(stream, (opcode & 0x001e) >> 1);
771 stream << ", ";
772 format_reg(stream, (opcode & 0x01e0) >> 5);
773 return 2 | SUPPORTED;
774
775 case 0x4a01: case 0x6a01:
776 util::stream_format(stream, "lsh%c ", BIT(opcode, 13) ? 'w' : 'b');
777 format_reg(stream, (opcode & 0x001e) >> 1);
778 stream << ", ";
779 format_reg(stream, (opcode & 0x01e0) >> 5);
780 return 2 | SUPPORTED;
781
782 case 0x4c01: case 0x6c01:
783 util::stream_format(stream, "xor%c ", BIT(opcode, 13) ? 'w' : 'b');
784 format_reg(stream, (opcode & 0x001e) >> 1);
785 stream << ", ";
786 format_reg(stream, (opcode & 0x01e0) >> 5);
787 return 2 | SUPPORTED;
788
789 case 0x4e01: case 0x6e01:
790 util::stream_format(stream, "cmp%c ", BIT(opcode, 13) ? 'w' : 'b');
791 format_reg(stream, (opcode & 0x001e) >> 1);
792 stream << ", ";
793 format_reg(stream, (opcode & 0x01e0) >> 5);
794 return 2 | SUPPORTED;
795
796 case 0x5001: case 0x7001:
797 util::stream_format(stream, "and%c ", BIT(opcode, 13) ? 'w' : 'b');
798 format_reg(stream, (opcode & 0x001e) >> 1);
799 stream << ", ";
800 format_reg(stream, (opcode & 0x01e0) >> 5);
801 return 2 | SUPPORTED;
802
803 case 0x5201: case 0x7201:
804 util::stream_format(stream, "addc%c ", BIT(opcode, 13) ? 'w' : 'b');
805 format_reg(stream, (opcode & 0x001e) >> 1);
806 stream << ", ";
807 format_reg(stream, (opcode & 0x01e0) >> 5);
808 return 2 | SUPPORTED;
809
810 case 0x5401:
811 if ((opcode & 0x01e0) != 0x01e0)
812 {
813 if ((opcode & 0x01e0) == 0x01c0)
814 stream << "jump ";
815 else
816 util::stream_format(stream, "j%s ", s_cc[(opcode & 0x01e0) >> 5]);
817 format_reg(stream, (opcode & 0x001e) >> 1);
818 return 2 | (opcode == 0x55dd ? STEP_OUT : 0) | SUPPORTED;
819 }
820 else
821 {
822 stream << "res";
823 return 2 | SUPPORTED;
824 }
825
826 case 0x5801: case 0x7801:
827 util::stream_format(stream, "mov%c ", BIT(opcode, 13) ? 'w' : 'b');
828 format_reg(stream, (opcode & 0x001e) >> 1);
829 stream << ", ";
830 format_reg(stream, (opcode & 0x01e0) >> 5);
831 return 2 | SUPPORTED;
832
833 case 0x5a01: case 0x7a01:
834 util::stream_format(stream, "subc%c ", BIT(opcode, 13) ? 'w' : 'b');
835 format_reg(stream, (opcode & 0x001e) >> 1);
836 stream << ", ";
837 format_reg(stream, (opcode & 0x01e0) >> 5);
838 return 2 | SUPPORTED;
839
840 case 0x5c01: case 0x7c01:
841 util::stream_format(stream, "or%c ", BIT(opcode, 13) ? 'w' : 'b');
842 format_reg(stream, (opcode & 0x001e) >> 1);
843 stream << ", ";
844 format_reg(stream, (opcode & 0x01e0) >> 5);
845 return 2 | SUPPORTED;
846
847 case 0x5e01: case 0x7e01:
848 util::stream_format(stream, "sub%c ", BIT(opcode, 13) ? 'w' : 'b');
849 format_reg(stream, (opcode & 0x001e) >> 1);
850 stream << ", ";
851 format_reg(stream, (opcode & 0x01e0) >> 5);
852 return 2 | SUPPORTED;
853
854 case 0x6000:
855 if (m_arch == cr16_arch::CR16A)
856 stream << "res";
857 else
858 {
859 stream << "mulsb ";
860 format_reg(stream, (opcode & 0x001e) >> 1);
861 stream << ", ";
862 format_reg(stream, (opcode & 0x01e0) >> 5);
863 }
864 return 2 | SUPPORTED;
865
866 case 0x6200:
867 if (m_arch == cr16_arch::CR16A)
868 stream << "res";
869 else
870 {
871 stream << "mulsw ";
872 format_reg(stream, (opcode & 0x001e) >> 1);
873 stream << ", ";
874 format_rpair(stream, (opcode & 0x01e0) >> 5);
875 }
876 return 2 | SUPPORTED;
877
878 case 0x6400: case 0x6600:
879 if (m_arch == cr16_arch::CR16A)
880 {
881 stream << "res";
882 return 2 | SUPPORTED;
883 }
884 else
885 {
886 stream << "movd ";
887 format_imm21(stream, u32(opcode & 0x0200) << 11 | u32(opcode & 0x000e) << 16 | u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2));
888 stream << ", ";
889 format_rpair(stream, (opcode & 0x01e0) >> 5);
890 return 4 | SUPPORTED;
891 }
892
893 case 0x6800: case 0x6a00:
894 util::stream_format(stream, "mov%cb ", BIT(opcode, 9) ? 'z' : 'x');
895 format_reg(stream, (opcode & 0x001e) >> 1);
896 stream << ", ";
897 format_reg(stream, (opcode & 0x01e0) >> 5);
898 return 2 | SUPPORTED;
899
900 case 0x6c00:
901 // Push and pop group
902 if (m_arch == cr16_arch::CR16A)
903 stream << "res";
904 else
905 {
906 if (BIT(opcode, 8))
907 stream << "popret ";
908 else if (BIT(opcode, 7))
909 stream << "pop ";
910 else
911 stream << "push ";
912 util::stream_format(stream, "$%d, ", ((opcode & 0x0060) >> 5) + 1);
913 format_reg(stream, (opcode & 0x001e) >> 1);
914 if (BIT(opcode, 8))
915 {
916 util::stream_format(stream, " ; %cMM", BIT(opcode, 7) ? 'L' : 'S');
917 return 2 | STEP_OUT | SUPPORTED;
918 }
919 }
920 return 2 | SUPPORTED;
921
922 case 0x6e00:
923 if ((opcode & 0x01c0) != 0x01c0)
924 {
925 util::stream_format(stream, "s%s ", s_cc[(opcode & 0x01e0) >> 5]);
926 format_reg(stream, (opcode & 0x001e) >> 1);
927 }
928 else
929 stream << "res";
930 return 2 | SUPPORTED;
931
932 case 0x7000:
933 stream << "lpr ";
934 format_reg(stream, (opcode & 0x001e) >> 1);
935 stream << ", ";
936 format_rproc(stream, (opcode & 0x01e0) >> 5);
937 return 2 | SUPPORTED;
938
939 case 0x7200:
940 stream << "spr ";
941 format_rproc(stream, (opcode & 0x01e0) >> 5);
942 stream << ", ";
943 format_reg(stream, (opcode & 0x001e) >> 1);
944 return 2 | SUPPORTED;
945
946 case 0x7400:
947 // Conditional or unconditional branch to large address
948 if ((opcode & 0x01e0) != 0x01e0 && m_arch != cr16_arch::CR16A)
949 {
950 if ((opcode & 0x01e0) == 0x01c0)
951 stream << "br ";
952 else
953 util::stream_format(stream, "b%s ", s_cc[(opcode & 0x01e0) >> 5]);
954 format_pc_disp21(stream, pc, u32(opcode & 0x000e) << 16 | u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2));
955 return 4 | SUPPORTED;
956 }
957 else
958 {
959 stream << "res";
960 return 2 | SUPPORTED;
961 }
962
963 case 0x7401:
964 // Jump and link to small address
965 stream << "jal ";
966 format_reg(stream, (opcode & 0x01e0) >> 5);
967 stream << ", ";
968 format_reg(stream, (opcode & 0x001e) >> 1);
969 return 2 | SUPPORTED;
970
971 case 0x7600:
972 // Branch and link to large address
973 if (m_arch == cr16_arch::CR16A)
974 {
975 stream << "res";
976 return 2 | SUPPORTED;
977 }
978 else
979 {
980 stream << "bal ";
981 format_rpair(stream, (opcode & 0x01e0) >> 5);
982 stream << ", ";
983 format_pc_disp21(stream, pc, u32(opcode & 0x000e) << 16 | u32(opcode & 0x0010) << 12 | opcodes.r16(pc + 2));
984 return 4 | STEP_OVER | SUPPORTED;
985 }
986
987 case 0x7601:
988 // TBIT reg, reg only exists as a word operation
989 stream << "tbit ";
990 format_reg(stream, (opcode & 0x001e) >> 1);
991 stream << ", ";
992 format_reg(stream, (opcode & 0x01e0) >> 5);
993 return 2 | SUPPORTED;
994
995 case 0x7800:
996 if (opcode == 0x79fe)
997 {
998 stream << "retx";
999 return 2 | STEP_OUT | SUPPORTED;
1000 }
1001 else
1002 {
1003 stream << "res";
1004 return 2 | SUPPORTED;
1005 }
1006
1007 case 0x7a00:
1008 if ((opcode & 0x01e0) == 0x01e0)
1009 {
1010 stream << "excp ";
1011 format_excp_vector(stream, (opcode & 0x001e) >> 1);
1012 return 2 | STEP_OVER | SUPPORTED;
1013 }
1014 else
1015 {
1016 stream << "res";
1017 return 2 | SUPPORTED;
1018 }
1019
1020 case 0x7c00:
1021 if (opcode == 0x7dde)
1022 stream << "di";
1023 else if (opcode == 0x7dfe)
1024 stream << "ei";
1025 else
1026 stream << "res";
1027 return 2 | SUPPORTED;
1028
1029 case 0x7e00:
1030 // Various special operations
1031 if (opcode == 0x7ffe)
1032 stream << "wait";
1033 else if (m_arch == cr16_arch::CR16A)
1034 stream << "res";
1035 else if ((opcode & 0x000c) == 0x0000)
1036 {
1037 stream << "muluw ";
1038 format_reg(stream, (opcode & 0x0012) >> 1);
1039 stream << ", ";
1040 format_rpair(stream, (opcode & 0x01e0) >> 5);
1041 }
1042 else if ((opcode & 0x011e) == 0x0004)
1043 {
1044 if (BIT(opcode, 7))
1045 stream << "storm ";
1046 else
1047 stream << "loadm ";
1048 util::stream_format(stream, "$%d", ((opcode & 0x0060) >> 5) + 1);
1049 }
1050 else if (opcode == 0x7fe6)
1051 stream << "eiwait";
1052 else
1053 stream << "res";
1054 return 2 | SUPPORTED;
1055
1056 default:
1057 stream << "res";
1058 return 2 | SUPPORTED;
1059 }
1060 }
1061