add undocumented instructions and dissasembler (#11050)

This commit is contained in:
tim lindner 2023-04-04 11:43:52 -07:00 committed by GitHub
parent 2a1ba144a5
commit 5dc861b772
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1053 additions and 798 deletions

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,8 @@
#ifndef MAME_CPU_M6809_6X09DASM_H
#define MAME_CPU_M6809_6X09DASM_H
#include <set>
#pragma once
class m6x09_base_disassembler : public util::disasm_interface
@ -37,22 +39,21 @@ protected:
class opcodeinfo;
public:
// General, or 6309 only?
enum m6x09_instruction_level
// General, undocumented, or 6309 only?
enum m6x09_instruction_level : uint8_t
{
M6x09_GENERAL,
HD6309_EXCLUSIVE
M6x09_GENERAL = 1,
M6809_UNDOCUMENTED = 2,
HD6309_EXCLUSIVE = 4
};
m6x09_base_disassembler(const opcodeinfo *opcodes, size_t opcode_count, m6x09_instruction_level level)
: m_opcodes(opcodes, opcode_count), m_level(level)
{
}
m6x09_base_disassembler(const opcodeinfo *opcodes, size_t opcode_count, uint32_t level);
virtual u32 opcode_alignment() const override;
virtual offs_t disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params) override;
protected:
enum m6x09_addressing_mode
enum m6x09_addressing_mode : uint8_t
{
INH, // Inherent
PSHS, PSHU, // Push
@ -67,33 +68,41 @@ protected:
IMM_RR, // Register-to-register
IMM_BW, // Bitwise operations (6309 only)
IMM_TFM, // Transfer from memory (6309 only)
PG1, // Switch to page 1 opcodes
PG2 // Switch to page 2 opcodes
PG2, // Switch to page 2 opcodes
PG3 // Switch to page 3 opcodes
};
// Opcode structure
class opcodeinfo
{
public:
constexpr opcodeinfo(uint16_t opcode, uint8_t length, const char *name, m6x09_addressing_mode mode, m6x09_instruction_level level, unsigned flags = 0)
: m_opcode(opcode), m_length(length), m_mode(mode), m_level(level), m_flags(flags), m_name(name)
constexpr opcodeinfo(uint16_t opcode, uint8_t operand_length, const char *name, m6x09_addressing_mode mode, uint32_t level, unsigned flags = 0)
: m_opcode(opcode), m_operand_length(operand_length), m_mode(mode), m_level(level), m_flags(flags), m_name(name)
{
}
uint16_t opcode() const { return m_opcode; }
uint8_t length() const { return m_length; }
uint8_t operand_length() const { return m_operand_length; }
m6x09_addressing_mode mode() const { return m_mode; }
m6x09_instruction_level level() const { return m_level; }
uint32_t level() const { return m_level; }
unsigned flags() const { return m_flags; }
const char *name() const { return m_name; }
struct compare
{
using is_transparent = void;
bool operator()(opcodeinfo const& lhs, opcodeinfo const& rhs) const;
bool operator()(uint16_t opcode, opcodeinfo const& rhs) const;
bool operator()(opcodeinfo const& lhs, uint16_t opcode) const;
};
private:
uint16_t m_opcode; // 8-bit opcode value
uint8_t m_length; // Opcode length in bytes
m6x09_addressing_mode m_mode : 6; // Addressing mode
m6x09_instruction_level m_level : 2; // General, or 6309 only?
unsigned m_flags; // Disassembly flags
const char * m_name; // Opcode name
uint16_t m_opcode; // 8-bit opcode value
uint8_t m_operand_length; // Opcode length in bytes
m6x09_addressing_mode m_mode; // Addressing mode
uint8_t m_level; // General, or 6309 only?
unsigned m_flags; // Disassembly flags
const char * m_name; // Opcode name
};
static const char *const m6x09_regs[5];
@ -105,14 +114,16 @@ protected:
virtual void register_register(std::ostream &stream, uint8_t pb) = 0;
private:
util::contiguous_sequence_wrapper<const opcodeinfo> m_opcodes;
m6x09_instruction_level m_level;
std::set<opcodeinfo, opcodeinfo::compare> m_opcodes;
uint32_t m_level;
uint16_t m_page;
const opcodeinfo *fetch_opcode(const data_buffer &opcodes, offs_t &p);
void assert_hd6309_exclusive()
{
if (m_level < HD6309_EXCLUSIVE)
if (!(m_level & HD6309_EXCLUSIVE))
throw false;
}
};
@ -120,7 +131,7 @@ private:
class m6x09_disassembler : public m6x09_base_disassembler
{
public:
m6x09_disassembler(m6x09_instruction_level level, const char teregs[16][4]);
m6x09_disassembler(uint32_t level, const char teregs[16][4]);
protected:
virtual void indexed(std::ostream &stream, uint8_t pb, const data_buffer &params, offs_t &p) override;

View File

@ -22,6 +22,10 @@
History:
January 2023 tlindner:
Add 6809 undocumented opcodes as described here:
https://github.com/hoglet67/6809Decoder/wiki/Undocumented-6809-Behaviours
July 2016 ErikGav:
Unify with 6309 pairs and quads (A+B=D, E+F=W, D+W=Q)
@ -214,6 +218,7 @@ void m6809_base_device::device_start()
save_item(NAME(m_addressing_mode));
save_item(NAME(m_reg));
save_item(NAME(m_cond));
save_item(NAME(m_free_run));
// set our instruction counter
set_icountptr(m_icount);
@ -233,6 +238,7 @@ void m6809_base_device::device_reset()
m_firq_line = false;
m_irq_line = false;
m_lds_encountered = false;
m_free_run = false;
m_dp = 0x00; // reset direct page register

View File

@ -279,6 +279,7 @@ private:
// other state
uint32_t m_state;
bool m_cond;
bool m_free_run;
// incidentals
int m_clock_divider;

View File

@ -13,22 +13,27 @@ MAIN:
m_ppc = m_pc;
debugger_instruction_hook(m_pc.w);
DISPATCH01:
// opcode fetch
m_lic_func(ASSERT_LINE);
@m_opcode = read_opcode();
m_lic_func(CLEAR_LINE);
if (m_free_run) goto FREERUN;
// dispatch opcode
switch(m_opcode)
{
case 0x00: case 0x01: %DIRECT; %NEG8; return;
case 0x03: case 0x02: %DIRECT; %COM8; return;
case 0x02: %DIRECT; %XNC8; return;
case 0x03: %DIRECT; %COM8; return;
case 0x04: case 0x05: %DIRECT; %LSR8; return;
case 0x06: %DIRECT; %ROR8; return;
case 0x07: %DIRECT; %ASR8; return;
case 0x08: %DIRECT; %ASL8; return;
case 0x09: %DIRECT; %ROL8; return;
case 0x0A: case 0x0B: %DIRECT; %DEC8; return;
case 0x0A: %DIRECT; %DEC8; return;
case 0x0B: %DIRECT; %XDEC8; return;
case 0x0C: %DIRECT; %INC8; return;
case 0x0D: %DIRECT; %TST8; return;
case 0x0E: %DIRECT; %JMP; return;
@ -38,10 +43,13 @@ MAIN:
case 0x11: %DISPATCH11; return;
case 0x12: %NOP; return;
case 0x13: %SYNC; return;
case 0x14: case 0x15: %FREERUN; return;
case 0x16: set_cond(true); %LBRANCH; return;
case 0x17: %LBSR; return;
case 0x18: %X18; return;
case 0x19: %DAA; return;
case 0x1A: set_imm(); %ORCC; return;
case 0x1B: %NOP; return;
case 0x1C: set_imm(); %ANDCC; return;
case 0x1D: %SEX; return;
case 0x1E: %EXG; return;
@ -72,60 +80,70 @@ MAIN:
case 0x35: %PULS; return;
case 0x36: %PSHU; return;
case 0x37: %PULU; return;
case 0x38: set_imm(); %XANDCC; return;
case 0x39: %RTS; return;
case 0x3A: %ABX; return;
case 0x3B: %RTI; return;
case 0x3C: %CWAI; return;
case 0x3D: %MUL; return;
case 0x3E: %XRES; return;
case 0x3F: %SWI; return;
case 0x40: case 0x41: set_a(); %NEG8; return;
case 0x43: case 0x42: set_a(); %COM8; return;
case 0x42: set_a(); %XNC8; return;
case 0x43: set_a(); %COM8; return;
case 0x44: case 0x45: set_a(); %LSR8; return;
case 0x46: set_a(); %ROR8; return;
case 0x47: set_a(); %ASR8; return;
case 0x48: set_a(); %ASL8; return;
case 0x49: set_a(); %ROL8; return;
case 0x4A: case 0x4B: set_a(); %DEC8; return;
case 0x4A: set_a(); %DEC8; return;
case 0x4B: set_a(); %XDEC8; return;
case 0x4C: set_a(); %INC8; return;
case 0x4D: set_a(); %TST8; return;
case 0x4E: set_a(); %JMP; return;
case 0x4E: set_a(); %XCLR8; return;
case 0x4F: set_a(); %CLR8; return;
case 0x50: case 0x51: set_b(); %NEG8; return;
case 0x53: case 0x52: set_b(); %COM8; return;
case 0x52: set_b(); %XNC8; return;
case 0x53: set_b(); %COM8; return;
case 0x54: case 0x55: set_b(); %LSR8; return;
case 0x56: set_b(); %ROR8; return;
case 0x57: set_b(); %ASR8; return;
case 0x58: set_b(); %ASL8; return;
case 0x59: set_b(); %ROL8; return;
case 0x5A: case 0x5B: set_b(); %DEC8; return;
case 0x5A: set_b(); %DEC8; return;
case 0x5B: set_b(); %XDEC8; return;
case 0x5C: set_b(); %INC8; return;
case 0x5D: set_b(); %TST8; return;
case 0x5E: set_b(); %JMP; return;
case 0x5E: set_b(); %XCLR8; return;
case 0x5F: set_b(); %CLR8; return;
case 0x60: case 0x61: %INDEXED; %NEG8; return;
case 0x63: case 0x62: %INDEXED; %COM8; return;
case 0x62: %INDEXED; %XNC8; return;
case 0x63: %INDEXED; %COM8; return;
case 0x64: case 0x65: %INDEXED; %LSR8; return;
case 0x66: %INDEXED; %ROR8; return;
case 0x67: %INDEXED; %ASR8; return;
case 0x68: %INDEXED; %ASL8; return;
case 0x69: %INDEXED; %ROL8; return;
case 0x6A: case 0x6B: %INDEXED; %DEC8; return;
case 0x6A: %INDEXED; %DEC8; return;
case 0x6B: %INDEXED; %XDEC8; return;
case 0x6C: %INDEXED; %INC8; return;
case 0x6D: %INDEXED; %TST8; return;
case 0x6E: %INDEXED; %JMP; return;
case 0x6F: %INDEXED; %CLR8; return;
case 0x70: case 0x71: %EXTENDED; %NEG8; return;
case 0x73: case 0x72: %EXTENDED; %COM8; return;
case 0x72: %EXTENDED; %XNC8; return;
case 0x73: %EXTENDED; %COM8; return;
case 0x74: case 0x75: %EXTENDED; %LSR8; return;
case 0x76: %EXTENDED; %ROR8; return;
case 0x77: %EXTENDED; %ASR8; return;
case 0x78: %EXTENDED; %ASL8; return;
case 0x79: %EXTENDED; %ROL8; return;
case 0x7A: case 0x7B: %EXTENDED; %DEC8; return;
case 0x7A: %EXTENDED; %DEC8; return;
case 0x7B: %EXTENDED; %XDEC8; return;
case 0x7C: %EXTENDED; %INC8; return;
case 0x7D: %EXTENDED; %TST8; return;
case 0x7E: %EXTENDED; %JMP; return;
@ -138,7 +156,7 @@ MAIN:
case 0x84: set_regop8(m_q.r.a); set_imm(); %AND8; return;
case 0x85: set_regop8(m_q.r.a); set_imm(); %BIT8; return;
case 0x86: set_regop8(m_q.r.a); set_imm(); %LD8; return;
case 0x87: set_regop8(m_q.r.a); set_imm(); %ST8; return;
case 0x87: set_regop8(m_q.r.a); set_imm(); %XST8; return;
case 0x88: set_regop8(m_q.r.a); set_imm(); %EOR8; return;
case 0x89: set_regop8(m_q.r.a); set_imm(); %ADC8; return;
case 0x8A: set_regop8(m_q.r.a); set_imm(); %OR8; return;
@ -146,7 +164,7 @@ MAIN:
case 0x8C: set_regop16(m_x); set_imm(); %CMP16; return;
case 0x8D: %BSR; return;
case 0x8E: set_regop16(m_x); set_imm(); %LD16; return;
case 0x8F: set_regop16(m_x); set_imm(); %ST16; return;
case 0x8F: set_regop16(m_x); set_imm(); %XST16; return;
case 0x90: set_regop8(m_q.r.a); %DIRECT; %SUB8; return;
case 0x91: set_regop8(m_q.r.a); %DIRECT; %CMP8; return;
@ -206,15 +224,15 @@ MAIN:
case 0xC4: set_regop8(m_q.r.b); set_imm(); %AND8; return;
case 0xC5: set_regop8(m_q.r.b); set_imm(); %BIT8; return;
case 0xC6: set_regop8(m_q.r.b); set_imm(); %LD8; return;
case 0xC7: set_regop8(m_q.r.b); set_imm(); %ST8; return;
case 0xC7: set_regop8(m_q.r.b); set_imm(); %XST8; return;
case 0xC8: set_regop8(m_q.r.b); set_imm(); %EOR8; return;
case 0xC9: set_regop8(m_q.r.b); set_imm(); %ADC8; return;
case 0xCA: set_regop8(m_q.r.b); set_imm(); %OR8; return;
case 0xCB: set_regop8(m_q.r.b); set_imm(); %ADD8; return;
case 0xCC: set_regop16(m_q.p.d); set_imm(); %LD16; return;
case 0xCD: set_regop16(m_q.p.d); set_imm(); %ST16; return;
case 0xCD: %FREERUN; return;
case 0xCE: set_regop16(m_u); set_imm(); %LD16; return;
case 0xCF: set_regop16(m_u); set_imm(); %ST16; return;
case 0xCF: set_regop16(m_u); set_imm(); %XST16; return;
case 0xD0: set_regop8(m_q.r.b); %DIRECT; %SUB8; return;
case 0xD1: set_regop8(m_q.r.b); %DIRECT; %CMP8; return;
@ -274,6 +292,9 @@ DISPATCH10:
@m_opcode = read_opcode();
switch(m_opcode)
{
case 0x10: %DISPATCH10; return;
case 0x11: %DISPATCH10; return;
case 0x20: set_cond(true); %LBRANCH; return;
case 0x21: set_cond(false); %LBRANCH; return;
case 0x22: set_cond(cond_hi()); %LBRANCH; return;
@ -291,35 +312,48 @@ DISPATCH10:
case 0x2E: set_cond(cond_gt()); %LBRANCH; return;
case 0x2F: set_cond(!cond_gt()); %LBRANCH; return;
case 0x3E: %XSWI2; return;
case 0x3F: %SWI2; return;
case 0x83: set_regop16(m_q.p.d); set_imm(); %CMP16; return;
case 0x87: set_regop8(m_q.r.a); set_imm(); %XST8; return;
case 0x8C: set_regop16(m_y); set_imm(); %CMP16; return;
case 0x8E: set_regop16(m_y); set_imm(); %LD16; return;
case 0x8F: set_regop16(m_y); set_imm(); %ST16; return;
case 0x8F: set_regop16(m_y); set_imm(); %XST16; return;
case 0x93: set_regop16(m_q.p.d); %DIRECT; %CMP16; return;
case 0x9C: set_regop16(m_y); %DIRECT; %CMP16; return;
case 0x9E: set_regop16(m_y); %DIRECT; %LD16; return;
case 0x9F: set_regop16(m_y); %DIRECT; %ST16; return;
case 0xA3: set_regop16(m_q.p.d); %INDEXED; %CMP16; return;
case 0xAC: set_regop16(m_y); %INDEXED; %CMP16; return;
case 0xAE: set_regop16(m_y); %INDEXED; %LD16; return;
case 0xAF: set_regop16(m_y); %INDEXED; %ST16; return;
case 0xB3: set_regop16(m_q.p.d); %EXTENDED; %CMP16; return;
case 0xBC: set_regop16(m_y); %EXTENDED; %CMP16; return;
case 0xBE: set_regop16(m_y); %EXTENDED; %LD16; return;
case 0xBF: set_regop16(m_y); %EXTENDED; %ST16; return;
case 0xC3: set_regop16(m_q.p.d); set_imm(); %XADD16; return;
case 0xC7: set_regop8(m_q.r.b); set_imm(); %XST8; return;
case 0xCE: set_regop16(m_s); set_imm(); %LD16; return;
case 0xCF: set_regop16(m_s); set_imm(); %ST16; return;
case 0xCF: set_regop16(m_s); set_imm(); %XST16; return;
case 0xD3: set_regop16(m_q.p.d); %DIRECT; %XADD16; return;
case 0xDE: set_regop16(m_s); %DIRECT; %LD16; return;
case 0xDF: set_regop16(m_s); %DIRECT; %ST16; return;
case 0xE3: set_regop16(m_q.p.d); %INDEXED; %XADD16; return;
case 0xEE: set_regop16(m_s); %INDEXED; %LD16; return;
case 0xEF: set_regop16(m_s); %INDEXED; %ST16; return;
case 0xF3: set_regop16(m_q.p.d); %EXTENDED; %XADD16; return;
case 0xFE: set_regop16(m_s); %EXTENDED; %LD16; return;
case 0xFF: set_regop16(m_s); %EXTENDED; %ST16; return;
default: %ILLEGAL; return;
default: %DISPATCH01; return;
}
return;
@ -327,16 +361,28 @@ DISPATCH11:
@m_opcode = read_opcode();
switch(m_opcode)
{
case 0x10: %DISPATCH11; return;
case 0x11: %DISPATCH11; return;
case 0x3E: %XFIRQ; return;
case 0x3F: %SWI3; return;
case 0x83: set_regop16(m_u); set_imm(); %CMP16; return;
case 0x8C: set_regop16(m_s); set_imm(); %CMP16; return;
case 0x87: set_regop8(m_q.r.a); set_imm(); %XST8; return;
case 0x8F: set_regop16(m_x); set_imm(); %XST16; return;
case 0x93: set_regop16(m_u); %DIRECT; %CMP16; return;
case 0x9C: set_regop16(m_s); %DIRECT; %CMP16; return;
case 0xC3: set_regop16(m_u); set_imm(); %XADD16; return;
case 0xC7: set_regop8(m_q.r.b); set_imm(); %XST8; return;
case 0xCF: set_regop16(m_u); set_imm(); %XST16; return;
case 0xA3: set_regop16(m_u); %INDEXED; %CMP16; return;
case 0xAC: set_regop16(m_s); %INDEXED; %CMP16; return;
case 0xB3: set_regop16(m_u); %EXTENDED; %CMP16; return;
case 0xBC: set_regop16(m_s); %EXTENDED; %CMP16; return;
default: %ILLEGAL; return;
case 0xD3: set_regop16(m_u); %DIRECT; %XADD16; return;
case 0xE3: set_regop16(m_u); %INDEXED; %XADD16; return;
case 0xF3: set_regop16(m_u); %EXTENDED; %XADD16; return;
default: %DISPATCH01; return;
}
return;
@ -600,6 +646,113 @@ TFR:
@dummy_vma(hd6309_native_mode() ? 2 : 4);
return;
FREERUN:
// A CPU test mode that increments the address bus until reset.
m_free_run = true;
return;
X18:
@m_temp.b.l = read_opcode_arg(m_pc.w);
m_temp.b.l = (m_cc & m_temp.b.l) << 1;
m_cc = m_temp.b.l | ((m_cc & 0x04) >> 1);
return;
XANDCC:
@eat(1);
goto ANDCC;
XRES:
set_ea(VECTOR_RESET_FFFE);
standard_irq_callback(M6809_SWI, m_pc.w);
set_regop16(m_s);
m_temp.w = entire_state_registers();
@dummy_read_opcode_arg(0);
@dummy_vma(1);
%PUSH_REGISTERS;
goto INTERRUPT_VECTOR;
XNC8:
if (m_cc & CC_C)
goto COM8;
else
goto NEG8;
XDEC8:
@m_temp.b.l = read_operand();
if (m_temp.b.l)
m_cc |= CC_C;
else
m_cc &= ~CC_C;
m_temp.b.l = set_flags<uint8_t>(CC_NZ, m_temp.b.l, 1, m_temp.b.l - 1);
if(!hd6309_native_mode() || !is_register_addressing_mode())
{
@dummy_read_opcode_arg(0);
;
}
@write_operand(m_temp.b.l);
return;
XCLR8:
@read_operand();
m_cc &= ~CC_NZV;
m_cc |= CC_Z;
if(!hd6309_native_mode() || !is_register_addressing_mode())
{
@dummy_read_opcode_arg(0);
;
}
@write_operand(0);
return;
XST8:
// TODO: Flag setting is much more complex, see:
// https://github.com/hoglet67/6809Decoder/wiki/Undocumented-6809-Behaviours#store-immediate
@read_operand();
set_flags(CC_NZV, regop8());
return;
XST16:
// TODO: Flag setting is much more complex, see:
// https://github.com/hoglet67/6809Decoder/wiki/Undocumented-6809-Behaviours#store-immediate
m_temp.b.h = read_operand(0);
write_memory(m_pc.w++, regop16().b.l);
set_flags(CC_NZV, regop16().w);
return;
XSWI2:
set_ea(VECTOR_SWI2);
standard_irq_callback(M6809_SWI, m_pc.w);
set_regop16(m_s);
m_temp.w = entire_state_registers();
@dummy_read_opcode_arg(0);
@dummy_vma(1);
%PUSH_REGISTERS;
goto INTERRUPT_VECTOR;
XADD16:
@m_temp.b.h = read_operand(0);
@m_temp.b.l = read_operand(1);
set_flags(CC_NZVC, regop16().w, m_temp.w, regop16().w + m_temp.w);
if(!hd6309_native_mode())
{
@dummy_read_opcode_arg(0);
;
}
return;
XFIRQ:
set_ea(VECTOR_FIRQ);
standard_irq_callback(M6809_SWI, m_pc.w);
set_regop16(m_s);
m_temp.w = entire_state_registers();
@dummy_read_opcode_arg(0);
@dummy_vma(1);
%PUSH_REGISTERS;
goto INTERRUPT_VECTOR;
ILLEGAL:
log_illegal();
return;