// license:BSD-3-Clause // copyright-holders:AJR /*************************************************************************** ELAN Microelectronics RISC II (RII) Series disassembler ***************************************************************************/ #include "emu.h" #include "util/disasmintf.h" #include "riidasm.h" #include "util/strformat.h" using osd::u32; using util::BIT; using offs_t = u32; // TODO: add register sets for other models const char *const epg3231_disassembler::s_regs[0x60] = { "INDF0", "FSR0", "PCL", "PCM", "PCH", "BSR", "STKPTR", "BSR1", "INDF1", "FSR1", "ACC", "TABPTRL", "TABPTRM", "TABPTRH", "CPUCON", "STATUS", "TRL2", "PRODL", "PRODH", "ADOTL", "ADOTH", "UARTTX", "UARTRX", "PORTA", "PORTB", "PORTC", "PORTD", "PORTE", "PORTF", "PORTG", "PORTH", "PORTI", "PFS", "STBCON", "INTCON", "INTSTA", "TRL0L", "TRL0H", "TRL1", "TR01CON", "TR2CON", "TRLIR", nullptr, "POST_ID", "ADCON", "PAINTEN", "PAINTSTA", "PAWAKE", "UARTCON", "UARTSTA", "PORTJ", "PORTK", "DCRB", "DCRC", "DCRDE", "DCRFG", "DCRHI", "DCRJK", "PBCON", "PCCON", "PLLF", "T0CL", "T0CH", "SPICON", "SPISTA", "SPRL", "SPRM", "SPRH", "SFCR", "ADDL", "ADDM", "ADDH", "ENV/SPHDR", "MTCON/SPHTCON", "MTRL/SPHTRL", "VOCON", "TR1C", "TR2C", "ADCF", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; riscii_disassembler::riscii_disassembler(const char *const regs[]) : util::disasm_interface() , m_regs(regs) { } u32 riscii_disassembler::opcode_alignment() const { return 1; } void riscii_disassembler::format_register(std::ostream &stream, u8 reg) const { if (reg < 0x60 && m_regs[reg] != nullptr) stream << m_regs[reg]; else util::stream_format(stream, "R%02Xh", reg); } void riscii_disassembler::format_immediate(std::ostream &stream, u8 data) const { stream << "#"; if (data >= 0xa0) stream << "0"; util::stream_format(stream, "%02Xh", data); } void riscii_disassembler::format_address(std::ostream &stream, u32 dst) const { util::stream_format(stream, "%05Xh", dst); } offs_t riscii_disassembler::disassemble(std::ostream &stream, offs_t pc, const riscii_disassembler::data_buffer &opcodes, const riscii_disassembler::data_buffer ¶ms) { u16 opcode = opcodes.r16(pc); offs_t words = 1; if (BIT(opcode, 15)) { if (BIT(opcode, 14)) { util::stream_format(stream, "%-8s", BIT(opcode, 13) ? "SCALL" : "SJMP"); format_address(stream, (pc & 0x3e000) | (opcode & 0x1fff)); if (BIT(opcode, 13)) words |= STEP_OVER; } else { u8 preg = (opcode & 0x1f00) >> 8; if (BIT(opcode, 13)) { util::stream_format(stream, "%-8s", "MOVPR"); format_register(stream, opcode & 0x00ff); stream << ","; format_register(stream, preg); } else { util::stream_format(stream, "%-8s", "MOVRP"); format_register(stream, preg); stream << ","; format_register(stream, opcode & 0x00ff); } } } else switch (opcode & 0xff00) { case 0x0000: if (opcode == 0x0000) stream << "NOP"; else if (opcode == 0x0001) stream << "WDTC"; else if (opcode == 0x0002) stream << "SLEP"; else if ((opcode & 0x00f0) == 0x0020) { util::stream_format(stream, "%-8s", "LJMP"); format_address(stream, u32(opcode & 0x000f) << 16 | opcodes.r16(pc + 1)); words = 2; } else if ((opcode & 0x00f0) == 0x0030) { util::stream_format(stream, "%-8s", "LCALL"); format_address(stream, u32(opcode & 0x000f) << 16 | opcodes.r16(pc + 1)); words = 2 | STEP_OVER; } else util::stream_format(stream, "%-8s%04Xh", "DW", opcode); break; case 0x0200: util::stream_format(stream, "%-8sA,", "OR"); format_register(stream, opcode & 0x00ff); break; case 0x0300: util::stream_format(stream, "%-8s", "OR"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x0400: util::stream_format(stream, "%-8sA,", "AND"); format_register(stream, opcode & 0x00ff); break; case 0x0500: util::stream_format(stream, "%-8s", "AND"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x0600: util::stream_format(stream, "%-8sA,", "XOR"); format_register(stream, opcode & 0x00ff); break; case 0x0700: util::stream_format(stream, "%-8s", "XOR"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x0800: util::stream_format(stream, "%-8s", "COMA"); format_register(stream, opcode & 0x00ff); break; case 0x0900: util::stream_format(stream, "%-8s", "COM"); format_register(stream, opcode & 0x00ff); break; case 0x0a00: util::stream_format(stream, "%-8s", "RRCA"); format_register(stream, opcode & 0x00ff); break; case 0x0b00: util::stream_format(stream, "%-8s", "RRC"); format_register(stream, opcode & 0x00ff); break; case 0x0c00: util::stream_format(stream, "%-8s", "RLCA"); format_register(stream, opcode & 0x00ff); break; case 0x0d00: util::stream_format(stream, "%-8s", "RLC"); format_register(stream, opcode & 0x00ff); break; case 0x0e00: util::stream_format(stream, "%-8s", "SWAPA"); format_register(stream, opcode & 0x00ff); break; case 0x0f00: util::stream_format(stream, "%-8s", "SWAP"); format_register(stream, opcode & 0x00ff); break; case 0x1000: util::stream_format(stream, "%-8sA,", "ADD"); format_register(stream, opcode & 0x00ff); break; case 0x1100: util::stream_format(stream, "%-8s", "ADD"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x1200: util::stream_format(stream, "%-8sA,", "ADC"); format_register(stream, opcode & 0x00ff); break; case 0x1300: util::stream_format(stream, "%-8s", "ADC"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x1400: util::stream_format(stream, "%-8sA,", "ADDDC"); format_register(stream, opcode & 0x00ff); break; case 0x1500: util::stream_format(stream, "%-8s", "ADDDC"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x1600: util::stream_format(stream, "%-8sA,", "SUB"); format_register(stream, opcode & 0x00ff); break; case 0x1700: util::stream_format(stream, "%-8s", "SUB"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x1800: util::stream_format(stream, "%-8sA,", "SUBB"); format_register(stream, opcode & 0x00ff); break; case 0x1900: util::stream_format(stream, "%-8s", "SUBB"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x1a00: util::stream_format(stream, "%-8sA,", "SUBDB"); format_register(stream, opcode & 0x00ff); break; case 0x1b00: util::stream_format(stream, "%-8s", "SUBDB"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x1c00: util::stream_format(stream, "%-8s", "INCA"); format_register(stream, opcode & 0x00ff); break; case 0x1d00: util::stream_format(stream, "%-8s", "INC"); format_register(stream, opcode & 0x00ff); break; case 0x1e00: util::stream_format(stream, "%-8s", "DECA"); format_register(stream, opcode & 0x00ff); break; case 0x1f00: util::stream_format(stream, "%-8s", "DEC"); format_register(stream, opcode & 0x00ff); break; case 0x2000: util::stream_format(stream, "%-8sA,", "MOV"); format_register(stream, opcode & 0x00ff); break; case 0x2100: util::stream_format(stream, "%-8s", "MOV"); format_register(stream, opcode & 0x00ff); stream << ",A"; break; case 0x2200: util::stream_format(stream, "%-8s", "SHRA"); format_register(stream, opcode & 0x00ff); break; case 0x2300: util::stream_format(stream, "%-8s", "SHLA"); format_register(stream, opcode & 0x00ff); break; case 0x2400: util::stream_format(stream, "%-8s", "CLR"); format_register(stream, opcode & 0x00ff); break; case 0x2500: util::stream_format(stream, "%-8s", "TEST"); format_register(stream, opcode & 0x00ff); break; case 0x2600: util::stream_format(stream, "%-8sA,", "MUL"); format_register(stream, opcode & 0x00ff); break; case 0x2700: util::stream_format(stream, "%-8s", "RPT"); format_register(stream, opcode & 0x00ff); words |= STEP_OVER | step_over_extra(1); break; case 0x2b00: switch (opcode & 0x00ff) { case 0xfe: stream << "RET"; words |= STEP_OUT; break; case 0xff: stream << "RETI"; words |= STEP_OUT; break; default: util::stream_format(stream, "%-8s%04Xh", "DW", opcode); break; } break; case 0x2c00: util::stream_format(stream, "%-8s0,", "TBRD"); format_register(stream, opcode & 0x00ff); break; case 0x2d00: util::stream_format(stream, "%-8s1,", "TBRD"); // increment mode format_register(stream, opcode & 0x00ff); break; case 0x2e00: util::stream_format(stream, "%-8s2,", "TBRD"); // decrement mode format_register(stream, opcode & 0x00ff); break; case 0x2f00: util::stream_format(stream, "%-8sA,", "TBRD"); format_register(stream, opcode & 0x00ff); break; case 0x3000: case 0x3100: case 0x3200: case 0x3300: case 0x3400: case 0x3500: case 0x3600: case 0x3700: case 0x3800: case 0x3900: case 0x3a00: case 0x3b00: case 0x3c00: case 0x3d00: case 0x3e00: case 0x3f00: util::stream_format(stream, "%-8s", "S0CALL"); format_address(stream, opcode & 0x0fff); words |= STEP_OVER; break; case 0x4000: util::stream_format(stream, "%-8s", "TBPTL"); format_immediate(stream, opcode & 0x00ff); break; case 0x4100: util::stream_format(stream, "%-8s", "TBPTM"); format_immediate(stream, opcode & 0x00ff); break; case 0x4200: util::stream_format(stream, "%-8s", "TBPTH"); format_immediate(stream, opcode & 0x00ff); break; case 0x4300: util::stream_format(stream, "%-8s", "BANK"); format_immediate(stream, opcode & 0x00ff); break; case 0x4400: util::stream_format(stream, "%-8sA,", "OR"); format_immediate(stream, opcode & 0x00ff); break; case 0x4500: util::stream_format(stream, "%-8sA,", "AND"); format_immediate(stream, opcode & 0x00ff); break; case 0x4600: util::stream_format(stream, "%-8sA,", "XOR"); format_immediate(stream, opcode & 0x00ff); break; case 0x4700: util::stream_format(stream, "%-8sA,", "JGE"); format_immediate(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x4800: util::stream_format(stream, "%-8sA,", "JLE"); format_immediate(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x4900: util::stream_format(stream, "%-8sA,", "JE"); format_immediate(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x4a00: util::stream_format(stream, "%-8sA,", "ADD"); format_immediate(stream, opcode & 0x00ff); break; case 0x4b00: util::stream_format(stream, "%-8sA,", "ADC"); format_immediate(stream, opcode & 0x00ff); break; case 0x4c00: util::stream_format(stream, "%-8sA,", "SUB"); format_immediate(stream, opcode & 0x00ff); break; case 0x4d00: util::stream_format(stream, "%-8sA,", "SUBB"); format_immediate(stream, opcode & 0x00ff); break; case 0x4e00: util::stream_format(stream, "%-8sA,", "MOV"); format_immediate(stream, opcode & 0x00ff); break; case 0x4f00: util::stream_format(stream, "%-8sA,", "MUL"); format_immediate(stream, opcode & 0x00ff); break; case 0x5000: util::stream_format(stream, "%-8sA,", "JDNZ"); format_register(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x5100: util::stream_format(stream, "%-8s", "JDNZ"); format_register(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x5200: util::stream_format(stream, "%-8sA,", "JINZ"); format_register(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x5300: util::stream_format(stream, "%-8s", "JINZ"); format_register(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x5500: util::stream_format(stream, "%-8sA,", "JGE"); format_register(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x5600: util::stream_format(stream, "%-8sA,", "JLE"); format_register(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x5700: util::stream_format(stream, "%-8sA,", "JE"); format_register(stream, opcode & 0x00ff); stream << ","; format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x5800: case 0x5900: case 0x5a00: case 0x5b00: case 0x5c00: case 0x5d00: case 0x5e00: case 0x5f00: util::stream_format(stream, "%-8s", "JBC"); format_register(stream, opcode & 0x00ff); util::stream_format(stream, ",%d,", (opcode & 0x0700) >> 8); format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x6000: case 0x6100: case 0x6200: case 0x6300: case 0x6400: case 0x6500: case 0x6600: case 0x6700: util::stream_format(stream, "%-8s", "JBS"); format_register(stream, opcode & 0x00ff); util::stream_format(stream, ",%d,", (opcode & 0x0700) >> 8); format_address(stream, (pc & 0x30000) | opcodes.r16(pc + 1)); words = 2; break; case 0x6800: case 0x6900: case 0x6a00: case 0x6b00: case 0x6c00: case 0x6d00: case 0x6e00: case 0x6f00: util::stream_format(stream, "%-8s", "BC"); format_register(stream, opcode & 0x00ff); util::stream_format(stream, ",%d", (opcode & 0x0700) >> 8); break; case 0x7000: case 0x7100: case 0x7200: case 0x7300: case 0x7400: case 0x7500: case 0x7600: case 0x7700: util::stream_format(stream, "%-8s", "BS"); format_register(stream, opcode & 0x00ff); util::stream_format(stream, ",%d", (opcode & 0x0700) >> 8); break; case 0x7800: case 0x7900: case 0x7a00: case 0x7b00: case 0x7c00: case 0x7d00: case 0x7e00: case 0x7f00: util::stream_format(stream, "%-8s", "BTG"); format_register(stream, opcode & 0x00ff); util::stream_format(stream, ",%d", (opcode & 0x0700) >> 8); break; default: util::stream_format(stream, "%-8s%04Xh", "DW", opcode); break; } return words | SUPPORTED; }