mame/src/devices/cpu/rii/riidasm.cpp
AJR a24caaede8 rii: Many updates
- Identify CPU type used by vreadere as ePG3231
- Add preliminary port I/O handlers and callbacks
- Add stub handlers and state variables for interrupt controller, timers, synthesizer, UART and SPI
- Fix TBRD addressing of external data memory
- Fix calculation of carry flag for normal additive operations
- Implement multi-byte carry/borrow for applicable registers
- Implement signed multiplication option
- Add internal stack buffer for saving PCH during calls/interrupts
2019-09-25 11:57:56 -04:00

567 lines
14 KiB
C++

// 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 &params)
{
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;
}