// license:BSD-3-Clause // copyright-holders:AJR /*************************************************************************** National Semiconductor DP8344 BCP disassembler ***************************************************************************/ #include "emu.h" #include "util/disasmintf.h" #include "bcpdasm.h" #include "util/strformat.h" using osd::u32; using util::BIT; using offs_t = u32; //************************************************************************** // BCP DISASSEMBLER //************************************************************************** dp8344_disassembler::dp8344_disassembler() : util::disasm_interface() { } u32 dp8344_disassembler::opcode_alignment() const { return 1; } const char *dp8344_disassembler::cc_to_string(u8 f, bool s) const { // f = 0, s = 1: Zero or EQual // f = 0, s = 0: Not Zero or Not EQual // f = 1, s = 1: Carry // f = 1, s = 0: No Carry // f = 2, s = 1: Overflow // f = 2, s = 0: No Overflow // f = 3, s = 1: Negative // f = 3, s = 0: Positive // f = 4, s = 1: Receiver Active // f = 4, s = 0: Not Receiver Active // f = 5, s = 1: Receiver Error // f = 5, s = 0: No Receiver Error // f = 6, s = 1: Data Available // f = 6, s = 0: No Data Available // f = 7, s = 1: Transmitter FIFO Full // f = 7, s = 0: Transmitter FIFO Not Full return std::array { "nz", "nc", "nv", "p", "nra", "nre", "ndav", "ntss", "z", "c", "v", "n", "ra", "re", "dav", "tss" }[f | (s ? 8 : 0)]; } const char *dp8344_disassembler::aop_to_string(u8 o) const { return std::array { "adda", "adca", "suba", "sbca", "anda", "ora", "xora", "move" }[o]; } void dp8344_disassembler::format_number(std::ostream &stream, u8 n) const { if (n >= 0xa0) stream << "0"; util::stream_format(stream, "%02Xh", n); } void dp8344_disassembler::format_address(std::ostream &stream, u16 nn) const { if (nn >= 0xa000) stream << "0"; util::stream_format(stream, "%04Xh", nn); } void dp8344_disassembler::format_register(std::ostream &stream, u8 r) const { stream << std::array { "CCR/DCR", "NCF/IBR", "ICR/ATR", "ACR/FBR", "GP0/RTR", "GP1/TSR", "GP2/TCR", "GP3/TMR", "GP4/GP4'", "GP5/GP5'", "GP6/GP6'", "GP7/GP7'", "IWLO", "IWHI", "IXLO", "IXHI", "IYLO", "IYHI", "IZLO", "IZHI", "GP8", "GP9", "GP10", "GP11", "GP12", "GP13", "GP14", "GP15", "TRL", "TRH", "ISP", "DS" }[r]; } void dp8344_disassembler::format_modified_index_register(std::ostream &stream, u8 ir, u8 m) const { if (m == 3) stream << "+"; util::stream_format(stream, "I%c", 'W' + ir); if (m == 0) stream << "-"; else if (m == 2) stream << "+"; } void dp8344_disassembler::format_interrupt_vector(std::ostream &stream, u8 v) const { switch (v) { case 0x1c: stream << "NMI"; break; case 0x04: stream << "RFF/DA/RA"; break; case 0x08: stream << "TFE"; break; case 0x0c: stream << "LTE"; break; case 0x10: stream << "BIRQ"; break; case 0x14: stream << "TO"; break; default: format_number(stream, v); break; } } offs_t dp8344_disassembler::disassemble(std::ostream &stream, offs_t pc, const dp8344_disassembler::data_buffer &opcodes, const dp8344_disassembler::data_buffer ¶ms) { u16 inst = opcodes.r16(pc); offs_t words = 1; switch (inst & 0xf000) { case 0x0000: // 0000-0FFF: ADD n,rsd (2 T-states) util::stream_format(stream, "%-8s", "add"); format_number(stream, (inst & 0x0ff0) >> 4); stream << ","; format_register(stream, inst & 0x000f); break; case 0x1000: // 1000-1FFF: MOVE rs,[IZ+n] (3 T-states) util::stream_format(stream, "%-8s", "move"); format_register(stream, inst & 0x000f); stream << ",[IZ+"; format_number(stream, (inst & 0x0ff0) >> 4); stream << "]"; break; case 0x2000: // 2000-2FFF: SUB n,rsd (2 T-states) util::stream_format(stream, "%-8s", "sub"); format_number(stream, (inst & 0x0ff0) >> 4); stream << ","; format_register(stream, inst & 0x000f); break; case 0x3000: // 3000-3FFF: CMP rs,n (2 T-states) util::stream_format(stream, "%-8s", "cmp"); format_register(stream, inst & 0x000f); stream << ","; format_number(stream, (inst & 0x0ff0) >> 4); break; case 0x4000: // 4000-4FFF: AND n,rsd (2 T-states) util::stream_format(stream, "%-8s", "and"); format_number(stream, (inst & 0x0ff0) >> 4); stream << ","; format_register(stream, inst & 0x000f); break; case 0x5000: // 5000-5FFF: OR n,rsd (2 T-states) util::stream_format(stream, "%-8s", "or"); format_number(stream, (inst & 0x0ff0) >> 4); stream << ","; format_register(stream, inst & 0x000f); break; case 0x6000: // 6000-6FFF: XOR n,rsd (2 T-states) util::stream_format(stream, "%-8s", "xor"); format_number(stream, (inst & 0x0ff0) >> 4); stream << ","; format_register(stream, inst & 0x000f); break; case 0x7000: // 7000-7FFF: BIT rs,n (2 T-states) util::stream_format(stream, "%-8s", "bit"); format_register(stream, inst & 0x000f); stream << ","; format_number(stream, (inst & 0x0ff0) >> 4); break; case 0x8000: if (!BIT(inst, 11)) { // 8000-87FF: JRMK Rs,b,m (4 T-states) util::stream_format(stream, "%-8s", "jrmk"); format_register(stream, inst & 0x001f); util::stream_format(stream, ",%d,%d", (inst & 0x00e0) >> 5, (inst & 0x0700) >> 8); } else if (!BIT(inst, 10)) { // 8800-8BFF: MOVE n,[Ir] (3 T-states) util::stream_format(stream, "%-8s", "move"); format_number(stream, (inst & 0x0380) >> 2 | (inst & 0x001f)); util::stream_format(stream, ",[I%c]", 'W' + ((inst & 0x0060) >> 5)); } else { words = 2; if (!BIT(inst, 9)) { // 8C00-8DFF, 0000-FFFF: LJMP Rs,p,s,nn (2 + 2 T-states) util::stream_format(stream, "%-8s", "ljmp"); } else { // 8E00-8FFF, 0000-FFFF: LCALL Rs,p,s,nn (2 + 2 T-states) util::stream_format(stream, "%-8s", "lcall"); words |= STEP_OVER; } format_register(stream, inst & 0x001f); util::stream_format(stream, ",%d,%d,", (inst & 0x00e0) >> 5, BIT(inst, 8)); format_address(stream, opcodes.r16(pc + 1)); } break; case 0x9000: // 9000-9FFF: MOVE [IZ+n],rd (3 T-states) util::stream_format(stream, "%-8s[IZ+", "move"); format_number(stream, (inst & 0x0ff0) >> 4); stream << "],"; format_register(stream, inst & 0x000f); break; case 0xa000: { if (inst < 0xae00) { // A000-A1FF: ADDA Rs,[mIr] (3 T-states) // A200-A3FF: ADCA Rs,[mIr] (3 T-states) // A400-A5FF: SUBA Rs,[mIr] (3 T-states) // A600-A7FF: SBCA Rs,[mIr] (3 T-states) // A800-A9FF: ANDA Rs,[mIr] (3 T-states) // AA00-ABFF: ORA Rs,[mIr] (3 T-states) // AC00-ADFF: XORA Rs,[mIr] (3 T-states) util::stream_format(stream, "%-8s", aop_to_string((inst & 0x0e00) >> 9)); format_register(stream, inst & 0x001f); stream << ",["; format_modified_index_register(stream, (inst & 0x0060) >> 5, (inst & 0x0180) >> 7); stream << "]"; } else if (!BIT(inst, 8)) { if (!BIT(inst, 7)) { // AE00-AE1F: CPL Rsd (2 T-states) util::stream_format(stream, "%-8s", "cpl"); format_register(stream, inst & 0x001f); } else { // AE80-AEF8: EXX ba,bb{,g} (2 T-states) util::stream_format(stream, "%-8s%cA,%cB", "exx", BIT(inst, 4) ? 'A' : 'M', BIT(inst, 3) ? 'A' : 'M'); switch (inst & 0x0060) { case 0x0000: // NCHG break; case 0x0020: stream << ",RI"; break; case 0x0040: stream << ",EI"; break; case 0x0060: stream << ",DI"; break; } } } else { // AF00-A7FF: RETF f,s{,{g}{,rf}} (2 or 3 T-states) // AF80-AFF0: RET {g{,rf}} (2 T-states) if (!BIT(inst, 7)) util::stream_format(stream, (inst & 0x0070) == 0 ? "r%s" : "r%-7s", cc_to_string(inst & 0x0007, BIT(inst, 3))); else util::stream_format(stream, (inst & 0x0070) == 0 ? "%s" : "%-8s", "ret"); switch (inst & 0x0060) { case 0x0000: if (BIT(inst, 4)) stream << "NCHG"; break; case 0x0020: stream << "RI"; break; case 0x0040: stream << "EI"; break; case 0x0060: stream << "DI"; break; } if (BIT(inst, 4)) stream << ",RF"; words |= STEP_OUT; } break; } case 0xb000: // B000-BFFF: MOVE n,rd (2 T-states) util::stream_format(stream, "%-8s", "move"); format_number(stream, (inst & 0x0ff0) >> 4); stream << ","; format_register(stream, inst & 0x000f); break; case 0xc000: switch (inst & 0xf80) { case 0x000: case 0x080: case 0x100: case 0x180: // C000-C1FF: MOVE [mIr],Rd (3 T-states) util::stream_format(stream, "%-8s[", "move"); format_modified_index_register(stream, (inst & 0x0060) >> 5, (inst & 0x0180) >> 7); stream << "],"; format_register(stream, inst & 0x001f); break; case 0x200: case 0x280: case 0x300: case 0x380: // C200-C3FF: MOVE Rs,[mIr] (3 T-states) util::stream_format(stream, "%-8s", "move"); format_register(stream, inst & 0x001f); stream << ",["; format_modified_index_register(stream, (inst & 0x0060) >> 5, (inst & 0x0180) >> 7); stream << "]"; break; case 0x400: // C400-C47F: MOVE [Ir+A],Rd (3 T-states) util::stream_format(stream, "%-8s[I%c+A],", "move", 'W' + ((inst & 0x0060) >> 5)); format_register(stream, inst & 0x001f); break; case 0x480: // C480-C4FF: MOVE Rs,[Ir+A] (3 T-states) util::stream_format(stream, "%-8s", "move"); format_register(stream, inst & 0x001f); util::stream_format(stream, ",[I%c+A]", 'W' + ((inst & 0x0060) >> 5)); break; case 0x800: case 0x880: // C800-C8FF: SHR Rsd,b (2 T-states) util::stream_format(stream, "%-8s", "shr"); format_register(stream, inst & 0x001f); util::stream_format(stream, ",%d", (inst & 0x00e0) >> 5); break; case 0x900: case 0x980: // C900-C9FF: SHL Rsd,b (2 T-states) util::stream_format(stream, "%-8s", "shl"); format_register(stream, inst & 0x001f); util::stream_format(stream, ",%d", (inst & 0x00e0) == 0 ? 0 : 8 - ((inst & 0x00e0) >> 5)); break; case 0xa00: case 0xa80: // CA00-CAFF: ROT Rsd,b (2 T-states) util::stream_format(stream, "%-8s", "rot"); format_register(stream, inst & 0x001f); util::stream_format(stream, ",%d", (inst & 0x00e0) >> 5); break; case 0xb00: case 0xb80: // CB00-CBFF: JMP n (3 T-states) util::stream_format(stream, "%-8s", "jmp"); format_address(stream, pc + 1 + s8(inst & 0x00ff)); break; case 0xc00: case 0xc80: // CC00-CCFF: CALL n (3 T-states) util::stream_format(stream, "%-8s", "call"); format_address(stream, pc + 1 + s8(inst & 0x00ff)); words |= STEP_OVER; break; case 0xd00: // CD00-DC60: LJMP [Ir] (2 T-states) util::stream_format(stream, "%-8s[I%c]", "ljmp", 'W' + ((inst & 0x0060) >> 5)); break; case 0xd80: // CD80-CD9F: JMP Rs (4 T-states) util::stream_format(stream, "%-8s", "jmp"); format_register(stream, inst & 0x001f); break; case 0xe00: // CE00: LJMP nn (2 + 2 T-states) util::stream_format(stream, "%-8s", "ljmp"); format_address(stream, opcodes.r16(pc + 1)); words = 2; break; case 0xe80: // CE80: LCALL nn (2 + 2 T-states) util::stream_format(stream, "%-8s", "lcall"); format_address(stream, opcodes.r16(pc + 1)); words = 2 | STEP_OVER; break; case 0xf80: // CF80-CFFF: TRAP v{,g'} (2 T-states) util::stream_format(stream, "%-8s", "trap"); format_interrupt_vector(stream, inst & 0x003f); if (BIT(inst, 6)) stream << ",DI"; words |= STEP_OVER; break; default: // invalid stream << "???"; break; } break; case 0xd000: // D000-DFFF: JMP f,s,n (2 or 3 T-states) util::stream_format(stream, "j%-7s", cc_to_string((inst & 0x0700) >> 8, BIT(inst, 11))); format_address(stream, pc + 1 + s8(inst & 0x00ff)); break; case 0xe000: case 0xf000: // E000-E3FF: ADDA Rs,Rd (2 T-states) // E400-E7FF: ADCA Rs,Rd (2 T-states) // E800-EBFF: SUBA Rs,Rd (2 T-states) // EC00-EFFF: SBCA Rs,Rd (2 T-states) // F000-F3FF: ANDA Rs,Rd (2 T-states) // F400-F7FF: ORA Rs,Rd (2 T-states) // F800-FBFF: XORA Rs,Rd (2 T-states) // FC00-FFFF: MOVE Rs,Rd (2 T-states) util::stream_format(stream, "%-8s", aop_to_string((inst & 0x1c00) >> 10)); format_register(stream, inst & 0x001f); stream << ","; format_register(stream, (inst & 0x03e0) >> 5); break; } return words | SUPPORTED; }