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