emu48-mirror/Sources/Emu48/DISASM.C
Gwenhael Le Moine 8f505d8844
2021-10-01: Updated to version 1.64
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
2024-03-20 08:15:25 +01:00

1847 lines
42 KiB
C

/*
* Disasm.c
*
* This file is part of Emu48, a ported version of x48
*
* Copyright (C) 1994 Eddie C. Dost
* Copyright (C) 1998 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
#pragma inline_depth(0)
#define TAB_SKIP 8
BOOL disassembler_mode = HP_MNEMONICS;
BOOL disassembler_symb = FALSE;
static LPCTSTR hex[] =
{
_T("0123456789ABCDEF"),
_T("0123456789abcdef")
};
static LPCTSTR opcode_0_tbl[32] =
{
/*
* HP Mnemonics
*/
_T("RTNSXM"), _T("RTN"), _T("RTNSC"), _T("RTNCC"),
_T("SETHEX"), _T("SETDEC"), _T("RSTK=C"), _T("C=RSTK"),
_T("CLRST"), _T("C=ST"), _T("ST=C"), _T("CSTEX"),
_T("P=P+1"), _T("P=P-1"), _T("(NULL)"), _T("RTI"),
/*
* Class Mnemonics
*/
_T("rtnsxm"), _T("rtn"), _T("rtnsc"), _T("rtncc"),
_T("sethex"), _T("setdec"), _T("push"), _T("pop"),
_T("clr.3 st"), _T("move.3 st, c"), _T("move.3 c, st"), _T("exg.3 c, st"),
_T("inc.1 p"), _T("dec.1 p"), _T("(null)"), _T("rti")
};
static LPCTSTR op_str_0[16] =
{
/*
* HP Mnemonics
*/
_T("A=A%cB"), _T("B=B%cC"), _T("C=C%cA"), _T("D=D%cC"),
_T("B=B%cA"), _T("C=C%cB"), _T("A=A%cC"), _T("C=C%cD"),
/*
* Class Mnemonics
*/
_T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"),
_T("a, b"), _T("b, c"), _T("c, a"), _T("d, c")
};
static LPCTSTR op_str_1[16] =
{
/*
* HP Mnemonics
*/
_T("DAT0=A"), _T("DAT1=A"), _T("A=DAT0"), _T("A=DAT1"),
_T("DAT0=C"), _T("DAT1=C"), _T("C=DAT0"), _T("C=DAT1"),
/*
* Class Mnemonics
*/
_T("a, (d0)"), _T("a, (d1)"), _T("(d0), a"), _T("(d1), a"),
_T("c, (d0)"), _T("c, (d1)"), _T("(d0), c"), _T("(d1), c")
};
static LPCTSTR in_str_80[32] =
{
/*
* HP Mnemonics
*/
_T("OUT=CS"), _T("OUT=C"), _T("A=IN"), _T("C=IN"),
_T("UNCNFG"), _T("CONFIG"), _T("C=ID"), _T("SHUTDN"),
NULL, _T("C+P+1"), _T("RESET"), _T("BUSCC"),
NULL, NULL, _T("SREQ?"), NULL,
/*
* Class Mnemonics
*/
_T("move.s c, out"), _T("move.3 c, out"), _T("move.4 in, a"), _T("move.4 in, c"),
_T("uncnfg"), _T("config"), _T("c=id"), _T("shutdn"),
NULL, _T("add.a p+1, c"), _T("reset"), _T("buscc"),
NULL, NULL, _T("sreq?"), NULL
};
static LPCTSTR in_str_808[32] =
{
/*
* HP Mnemonics
*/
_T("INTON"), NULL, NULL, _T("BUSCB"),
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
_T("PC=(A)"), _T("BUSCD"), _T("PC=(C)"), _T("INTOFF"),
/*
* Class Mnemonics
*/
_T("inton"), NULL, NULL, _T("buscb"),
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
_T("jmp (a)"), _T("buscd"), _T("jmp (c)"), _T("intoff")
};
static LPCTSTR op_str_81[8] =
{
/*
* HP Mnemonics
*/
_T("A"), _T("B"), _T("C"), _T("D"),
/*
* Class Mnemonics
*/
_T("a"), _T("b"), _T("c"), _T("d")
};
static LPCTSTR in_str_81b[32] =
{
/*
* HP Mnemonics
*/
NULL, NULL, _T("PC=A"), _T("PC=C"),
_T("A=PC"), _T("C=PC"), _T("APCEX"), _T("CPCEX"),
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
/*
* Class Mnemonics
*/
NULL, NULL, _T("jmp a"), _T("jmp c"),
_T("move.a pc, a"), _T("move.a pc, c"), _T("exg.a a, pc"), _T("exg.a c, pc"),
NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL
};
static LPCTSTR in_str_9[16] =
{
/*
* HP Mnemonics
*/
_T("="), _T("#"), _T("="), _T("#"),
_T(">"), _T("<"), _T(">="), _T("<="),
/*
* Class Mnemonics
*/
_T("eq"), _T("ne"), _T("eq"), _T("ne"),
_T("gt"), _T("lt"), _T("ge"), _T("le")
};
static LPCTSTR op_str_9[16] =
{
/*
* HP Mnemonics
*/
_T("?A%sB"), _T("?B%sC"), _T("?C%sA"), _T("?D%sC"),
_T("?A%s0"), _T("?B%s0"), _T("?C%s0"), _T("?D%s0"),
/*
* Class Mnemonics
*/
_T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"),
_T("a, 0"), _T("b, 0"), _T("c, 0"), _T("d, 0")
};
static LPCTSTR op_str_af[32] =
{
/*
* HP Mnemonics
*/
_T("A=A%sB"), _T("B=B%sC"), _T("C=C%sA"), _T("D=D%sC"),
_T("A=A%sA"), _T("B=B%sB"), _T("C=C%sC"), _T("D=D%sD"),
_T("B=B%sA"), _T("C=C%sB"), _T("A=A%sC"), _T("C=C%sD"),
_T("A=B%sA"), _T("B=C%sB"), _T("C=A%sC"), _T("D=C%sD"),
/*
* Class Mnemonics
*/
_T("b, a"), _T("c, b"), _T("a, c"), _T("c, d"),
_T("a, a"), _T("b, b"), _T("c, c"), _T("d, d"),
_T("a, b"), _T("b, c"), _T("c, a"), _T("d, c"),
_T("b, a"), _T("c, b"), _T("a, c"), _T("c, d")
};
static LPCTSTR hp_reg_1_af = _T("ABCDABCDBCACABAC");
static LPCTSTR hp_reg_2_af = _T("0000BCACABCDBCCD");
static LPCTSTR field_tbl[32] =
{
/*
* HP Mnemonics
*/
_T("P"), _T("WP"), _T("XS"), _T("X"),
_T("S"), _T("M"), _T("B"), _T("W"),
_T("P"), _T("WP"), _T("XS"), _T("X"),
_T("S"), _T("M"), _T("B"), _T("A"),
/*
* Class Mnemonics
*/
_T(".p"), _T(".wp"), _T(".xs"), _T(".x"),
_T(".s"), _T(".m"), _T(".b"), _T(".w"),
_T(".p"), _T(".wp"), _T(".xs"), _T(".x"),
_T(".s"), _T(".m"), _T(".b"), _T(".a")
};
static LPCTSTR hst_bits[8] =
{
/*
* HP Mnemonics
*/
_T("XM"), _T("SB"), _T("SR"), _T("MP"),
/*
* Class Mnemonics
*/
_T("xm"), _T("sb"), _T("sr"), _T("mp")
};
// general functions
static BYTE read_nibble (DWORD *p)
{
return GetMemNib(p);
}
static int read_int (DWORD *addr, int n)
{
int i, t;
for (i = 0, t = 0; i < n; i++)
t |= read_nibble (addr) << (i * 4);
return t;
}
static LPTSTR append_str (LPTSTR buf, LPCTSTR str)
{
while ((*buf = *str++))
buf++;
return buf;
}
static LPTSTR append_tab (LPTSTR buf)
{
int n;
LPTSTR p;
n = lstrlen (buf);
p = &buf[n];
n = TAB_SKIP - (n % TAB_SKIP);
while (n--)
*p++ = _T(' ');
*p = 0;
return p;
}
static __inline LPTSTR append_field (LPTSTR buf, BYTE fn)
{
return append_str (buf, field_tbl[fn + 16 * disassembler_mode]);
}
static LPTSTR append_imm_nibble (LPTSTR buf, DWORD *addr, int n)
{
int i;
BYTE t[16];
LPTSTR p = buf; // save start of buffer
if (disassembler_mode == CLASS_MNEMONICS)
{
*buf++ = _T('#');
if (n > 1)
*buf++ = _T('$');
}
else // HP Mnemonics
{
if (n > 1) // hex mode
*buf++ = _T('#'); // insert hex header
}
if (n > 1)
{
DWORD dwAddr = 0; // decoded address
for (i = 0; i < n; i++)
t[i] = read_nibble (addr);
for (i = n - 1; i >= 0; i--)
{
dwAddr = (dwAddr << 4) | t[i];
*buf++ = hex[disassembler_mode][t[i]];
}
*buf = 0;
if (n == 5) // 5 nibble address
{
LPCTSTR lpszName;
if (disassembler_symb && (lpszName = RplGetName(dwAddr)) != NULL)
{
// overwrite number with symbolic name
buf = append_str(p, _T("="));
buf = append_str(buf, lpszName);
}
}
}
else // single nibble
{
buf += wsprintf (buf, _T("%d"), read_nibble (addr));
}
return buf;
}
static LPTSTR append_numaddr (LPTSTR buf, DWORD addr)
{
int shift;
if (disassembler_mode == CLASS_MNEMONICS)
{
*buf++ = _T('$');
}
for (shift = 16; shift >= 0; shift -= 4)
*buf++ = hex[disassembler_mode][(addr >> shift) & 0xF];
*buf = 0;
return buf;
}
static LPTSTR append_addr (LPTSTR buf, DWORD addr)
{
LPCTSTR lpszName;
if (disassembler_symb && (lpszName = RplGetName(addr)) != NULL)
{
buf = append_str(buf, _T("="));
buf = append_str(buf, lpszName);
}
else // no symbol
{
buf = append_numaddr (buf, addr);
}
return buf;
}
static LPTSTR append_r_addr (LPTSTR buf, DWORD *pc, long disp, int n, int offset)
{
LPCTSTR lpszName;
long sign;
sign = 1 << (n * 4 - 1);
if (disp & sign) // negative value?
disp |= ~(sign - 1); // expand it to long
*pc = (*pc + disp) & 0xFFFFF;
if (disassembler_symb && (lpszName = RplGetName(*pc)) != NULL)
{
buf = append_str(buf, _T("=")); // show symbol
buf = append_str(buf, lpszName);
}
else // no symbol
{
if (disp < 0)
{
buf = append_str(buf, _T("-"));
disp = -disp - offset;
}
else
{
buf = append_str(buf, _T("+"));
disp += offset;
}
buf = append_numaddr(buf, disp); // show offset
buf = append_str(buf, _T(" ["));
buf = append_numaddr(buf, *pc); // show absolute address
buf = append_str(buf, _T("]"));
}
return buf;
}
static LPTSTR append_hst_bits (LPTSTR buf, int n)
{
int i;
LPTSTR p = buf;
switch (disassembler_mode)
{
case HP_MNEMONICS:
for (i = 0; i < 4; i++)
if (n & (1 << i))
{
p = append_str (p, hst_bits[i + 4 * disassembler_mode]);
}
break;
case CLASS_MNEMONICS:
while (lstrlen (buf) < 4 * TAB_SKIP)
p = append_tab (buf);
p = &buf[lstrlen (buf)];
p = append_str (p, _T("; hst bits: "));
for (buf = p, i = 0; i < 4; i++)
if (n & (1 << i))
{
if (p != buf)
p = append_str (p, _T(", "));
p = append_str (p, hst_bits[i + 4 * disassembler_mode]);
}
break;
default:
p = append_str (p, _T("Unknown disassembler mode"));
break;
}
return p;
}
static LPTSTR disasm_1 (DWORD *addr, LPTSTR out)
{
BYTE n;
BYTE fn;
LPTSTR p;
TCHAR buf[20];
TCHAR c;
p = out;
switch (n = read_nibble (addr))
{
case 0:
case 1:
fn = read_nibble (addr);
c = (fn < 8); // flag for operand register
fn = (fn & 7); // get register number
if (fn > 4) // unsupported opcode
fn -= 4; // map to valid scratch register
switch (disassembler_mode)
{
case HP_MNEMONICS:
c = (TCHAR) (c ? _T('A') : _T('C'));
if (n == 0)
wsprintf (buf, _T("R%d=%c"), fn, c);
else
wsprintf (buf, _T("%c=R%d"), c, fn);
p = append_str (out, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("move.w"));
p = append_tab (out);
c = (TCHAR) (c ? _T('a') : _T('c'));
if (n == 0)
wsprintf (buf, _T("%c, r%d"), c, fn);
else
wsprintf (buf, _T("r%d, %c"), fn, c);
p = append_str (p, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 2:
fn = read_nibble (addr);
c = (fn < 8); // flag for operand register
fn = (fn & 7); // get register number
if (fn > 4) // unsupported opcode
fn -= 4; // map to valid scratch register
switch (disassembler_mode)
{
case HP_MNEMONICS:
c = (TCHAR) (c ? _T('A') : _T('C'));
wsprintf (buf, _T("%cR%dEX"), c, fn);
p = append_str (out, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("exg.w"));
p = append_tab (out);
c = (TCHAR) (c ? _T('a') : _T('c'));
wsprintf (buf, _T("%c, r%d"), c, fn);
p = append_str (p, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 3:
n = read_nibble (addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
c = (n & 4) ? _T('C') : _T('A');
if (n & 2)
{
if (n < 8)
{
wsprintf (buf, _T("%cD%dEX"), c, (n & 1));
}
else
{
wsprintf (buf, _T("%cD%dXS"), c, (n & 1));
}
}
else
{
if (n < 8)
{
wsprintf (buf, _T("D%d=%c"), (n & 1), c);
}
else
{
wsprintf (buf, _T("D%d=%cS"), (n & 1), c);
}
}
p = append_str (out, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, (n & 2) ? _T("exg.") : _T("move."));
p = append_str (p, (n < 8) ? _T("a") : _T("4"));
p = append_tab (out);
c = (n & 4) ? _T('c') : _T('a');
wsprintf (buf, _T("%c, d%d"), c, (n & 1));
p = append_str (p, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 4:
case 5:
fn = read_nibble (addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
p = append_str (out, op_str_1[(fn & 7) + 8 * disassembler_mode]);
p = append_tab (out);
if (n == 4)
{
p = append_str (p, (fn < 8) ? _T("A") : _T("B"));
}
else
{
n = read_nibble (addr);
if (fn < 8)
{
p = append_field (p, n);
}
else
{
wsprintf (buf, _T("%d"), n + 1);
p = append_str (p, buf);
}
}
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("move"));
if (n == 4)
{
p = append_str (p, _T("."));
p = append_str (p, (fn < 8) ? _T("a") : _T("b"));
}
else
{
n = read_nibble (addr);
if (fn < 8)
{
p = append_field (p, n);
}
else
{
wsprintf (buf, _T(".%d"), n + 1);
p = append_str (p, buf);
}
}
p = append_tab (out);
p = append_str (p, op_str_1[(fn & 7) + 8 * disassembler_mode]);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 6:
case 7:
case 8:
case 0xc:
fn = read_nibble (addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (n == 6 || n == 8)
p = append_str (out, _T("D0=D0"));
else
p = append_str (out, _T("D1=D1"));
if (n < 8)
p = append_str (p, _T("+"));
else
p = append_str (p, _T("-"));
p = append_tab (out);
wsprintf (buf, _T("%d"), fn + 1);
p = append_str (p, buf);
break;
case CLASS_MNEMONICS:
if (n < 8)
p = append_str (out, _T("add.a"));
else
p = append_str (out, _T("sub.a"));
p = append_tab (out);
wsprintf (buf, _T("#%d, "), fn + 1);
p = append_str (p, buf);
if (n == 6 || n == 8)
p = append_str (p, _T("d0"));
else
p = append_str (p, _T("d1"));
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 9:
case 0xa:
case 0xb:
case 0xd:
case 0xe:
case 0xf:
c = (TCHAR) ((n < 0xd) ? _T('0') : _T('1'));
switch (n & 3)
{
case 1:
n = 2;
break;
case 2:
n = 4;
break;
case 3:
n = 5;
break;
}
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("D%c=(%d)"), c, n);
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, addr, n);
break;
case CLASS_MNEMONICS:
if (n == 5)
{
wsprintf (buf, _T("move.a"));
}
else
if (n == 4)
{
wsprintf (buf, _T("move.as"));
}
else
{
wsprintf (buf, _T("move.b"));
}
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, addr, n);
wsprintf (buf, _T(", d%c"), c);
p = append_str (p, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
default:
break;
}
return p;
}
static LPTSTR disasm_8 (DWORD *addr, LPTSTR out)
{
BYTE n;
BYTE fn;
BYTE rn;
LPTSTR p = out;
TCHAR c;
TCHAR buf[20];
DWORD disp, pc;
fn = read_nibble (addr);
switch (fn)
{
case 0:
n = read_nibble (addr);
if (NULL != (p = (LPTSTR) in_str_80[n + 16 * disassembler_mode]))
{
p = append_str (out, p);
return p;
}
switch (n)
{
case 8:
fn = read_nibble (addr);
if (NULL != (p = (LPTSTR) in_str_808[fn + 16 * disassembler_mode]))
{
p = append_str (out, p);
return p;
}
switch (fn)
{
case 1:
n = read_nibble (addr);
if (n == 0)
{
switch (disassembler_mode)
{
case HP_MNEMONICS:
p = append_str (out, _T("RSI"));
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("rsi"));
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
}
else
p = out; // illegal opcode, no output
break;
case 2:
n = read_nibble (addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (n < 5)
{
wsprintf (buf, _T("LA(%d)"), n + 1);
}
else
{
wsprintf (buf, _T("LAHEX"));
}
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, addr, n + 1);
break;
case CLASS_MNEMONICS:
wsprintf (buf, _T("move.%d"), n + 1);
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, addr, n + 1);
wsprintf (buf, _T(", a.p"));
p = append_str (p, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 4:
case 5:
case 8:
case 9:
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("%cBIT=%d"), (fn & 8) ? _T('C') : _T('A'),
(fn & 1) ? 1 : 0);
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, addr, 1);
break;
case CLASS_MNEMONICS:
p = append_str (out, (fn & 1) ? _T("bset") : _T("bclr"));
p = append_tab (out);
p = append_imm_nibble (p, addr, 1);
p = append_str (p, (fn & 8) ? _T(", c") : _T(", a"));
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 6:
case 7:
case 0xa:
case 0xb:
n = read_nibble (addr);
pc = *addr;
disp = read_int (addr, 2);
switch (disassembler_mode)
{
case HP_MNEMONICS:
c = (TCHAR) ((fn < 0xa) ? _T('A') : _T('C'));
wsprintf (buf, _T("?%cBIT=%d"), c, (fn & 1) ? 1 : 0);
p = append_str (out, buf);
p = append_tab (out);
wsprintf (buf, _T("%d"), n);
p = append_str (p, buf);
if (disp != 0)
{
p = append_str (p, _T(", GOYES "));
p = append_r_addr (p, &pc, disp, 2, 5);
}
else
p = append_str (p, _T(", RTNYES"));
break;
case CLASS_MNEMONICS:
c = (TCHAR) ((fn < 0xa) ? _T('a') : _T('c'));
p = append_str (out, (disp == 0) ? _T("rt") : _T("b"));
p = append_str (p, (fn & 1) ? _T("bs") : _T("bc"));
p = append_tab (out);
wsprintf (buf, _T("#%d, %c"), n, c);
p = append_str (p, buf);
if (disp != 0)
{
p = append_str (p, _T(", "));
p = append_r_addr (p, &pc, disp, 2, 5);
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
default:
break;
}
break;
case 0xc:
case 0xd:
case 0xf:
fn = read_nibble (addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, (n == 0xf) ? _T("%c%cEX") : _T("%c=%c"),
(n == 0xd) ? _T('P') : _T('C'), (n == 0xd) ? _T('C') : _T('P'));
p = append_str (out, buf);
p = append_tab (out);
wsprintf (buf, _T("%d"), fn);
p = append_str (p, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, (n == 0xf) ? _T("exg.1") : _T("move.1"));
p = append_tab (out);
wsprintf (buf, (n == 0xd) ? _T("p, c.%d") : _T("c.%d, p"), fn);
p = append_str (p, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
default:
break;
}
break;
case 1:
switch (n = read_nibble (addr))
{
case 0:
case 1:
case 2:
case 3:
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("%sSLC"), op_str_81[(n & 3) + 4 * disassembler_mode]);
p = append_str (out, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("rol.w"));
p = append_tab (out);
p = append_str (p, _T("#4, "));
p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 4:
case 5:
case 6:
case 7:
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("%sSRC"), op_str_81[(n & 3) + 4 * disassembler_mode]);
p = append_str (out, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("ror.w"));
p = append_tab (out);
p = append_str (p, _T("#4, "));
p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 8:
fn = read_nibble (addr); // get number
n = read_nibble (addr); // get register selector
if ((n & 7) > 3) // illegal opcode
break; // no output
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("%s=%s%cCON"),
op_str_81[(n & 3) + 4 * disassembler_mode],
op_str_81[(n & 3) + 4 * disassembler_mode],
(n < 8) ? _T('+') : _T('-'));
p = append_str (out, buf);
p = append_tab (out);
p = append_field (p, fn);
fn = read_nibble (addr);
wsprintf (buf, _T(", %d"), fn + 1);
p = append_str (p, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, (n < 8) ? _T("add") : _T("sub"));
p = append_field (p, fn);
p = append_tab (out);
fn = read_nibble (addr);
wsprintf (buf, _T("#%d, "), fn + 1);
p = append_str (p, buf);
p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 9:
fn = read_nibble (addr); // get field selector
n = read_nibble (addr); // get register selector
if (n > 3) // illegal opcode
break; // no output
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("%sSRB.F"), op_str_81[n + 4 * disassembler_mode]);
p = append_str (out, buf);
p = append_tab (out);
p = append_field (p, fn);
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("lsr"));
p = append_field (p, fn);
p = append_tab (out);
p = append_str (p, _T("#1, "));
p = append_str (p, op_str_81[n + 4 * disassembler_mode]);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 0xa:
fn = read_nibble (addr);
n = read_nibble (addr);
if (n > 2) // illegal opcode
break; // no output
c = (TCHAR) read_nibble (addr);
rn = (c & 7); // get register number
c = (c < 8); // flag for operand register
if (rn > 4) // unsupported opcode
rn -= 4; // map to valid scratch register
switch (disassembler_mode)
{
case HP_MNEMONICS:
c = (TCHAR) (c ? _T('A') : _T('C'));
if (n == 2)
{
wsprintf (buf, _T("%cR%dEX.F"), c, rn);
}
else
if (n == 1)
{
wsprintf (buf, _T("%c=R%d.F"), c, rn);
}
else
{
wsprintf (buf, _T("R%d=%c.F"), rn, c);
}
p = append_str (out, buf);
p = append_tab (out);
p = append_field (p, fn);
break;
case CLASS_MNEMONICS:
c = (TCHAR) (c ? _T('a') : _T('c'));
p = append_str (out, (n == 2) ? _T("exg") : _T("move"));
p = append_field (p, fn);
p = append_tab (out);
if (n == 1)
{
wsprintf (buf, _T("r%d"), rn);
p = append_str (p, buf);
}
else
*p++ = c;
p = append_str (p, _T(", "));
if (n == 1)
*p++ = c;
else
{
wsprintf (buf, _T("r%d"), rn);
p = append_str (p, buf);
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 0xb:
n = read_nibble (addr);
if ((n < 2) || (n > 7)) // illegal opcode
break; // no output
p = append_str (out, in_str_81b[n + 16 * disassembler_mode]);
break;
case 0xc:
case 0xd:
case 0xe:
case 0xf:
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("%sSRB"), op_str_81[(n & 3) + 4 * disassembler_mode]);
p = append_str (out, buf);
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("lsr.w"));
p = append_tab (out);
p = append_str (p, _T("#1, "));
p = append_str (p, op_str_81[(n & 3) + 4 * disassembler_mode]);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
default:
break;
}
break;
case 2:
n = read_nibble (addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (n == 0xf)
{
p = append_str (out, _T("CLRHST"));
}
else
{
// when not only one bit is set the HS=0 opcode is used
if (n != 1 && n != 2 && n != 4 && n != 8)
{
p = append_str (out, _T("HS=0"));
p = append_tab (out);
wsprintf (buf, _T("%d"), n);
p = append_str (p, buf);
}
else
{
p = append_hst_bits (out, n);
p = append_str (p, _T("=0"));
}
}
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("clr.1"));
p = append_tab (out);
wsprintf (buf, _T("#%d, hst"), n);
p = append_str (p, buf);
p = append_hst_bits (out, n);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 3:
n = read_nibble (addr);
pc = *addr;
disp = read_int (addr, 2);
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (n != 1 && n != 2 && n != 4 && n != 8)
{
p = append_str (out, _T("?HS=0"));
p = append_tab (out);
wsprintf (buf, _T("%d, "), n);
p = append_str (p, buf);
}
else
{
p = append_str (out, _T("?"));
p = append_hst_bits (p, n);
p = append_str (p, _T("=0"));
p = append_tab (out);
}
if (disp != 0)
{
p = append_str (p, _T("GOYES "));
p = append_r_addr (p, &pc, disp, 2, 3);
}
else
p = append_str (p, _T("RTNYES"));
break;
case CLASS_MNEMONICS:
p = append_str (out, (disp == 0) ? _T("rt") : _T("b"));
p = append_str (p, _T("eq.1"));
p = append_tab (out);
wsprintf (buf, _T("#%d, hst"), n);
p = append_str (p, buf);
if (disp != 0)
{
p = append_str (p, _T(", "));
p = append_r_addr (p, &pc, disp, 2, 3);
}
p = append_hst_bits (out, n);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 4:
case 5:
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("ST=%d"), (fn == 4) ? 0 : 1);
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, addr, 1);
break;
case CLASS_MNEMONICS:
p = append_str (out, (fn == 4) ? _T("bclr") : _T("bset"));
p = append_tab (out);
p = append_imm_nibble (p, addr, 1);
p = append_str (p, _T(", st"));
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 6:
case 7:
n = read_nibble (addr);
pc = *addr;
disp = read_int (addr, 2);
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("?ST=%d"), (fn == 6) ? 0 : 1);
p = append_str (out, buf);
p = append_tab (out);
wsprintf (buf, _T("%d"), n);
p = append_str (p, buf);
if (disp != 0)
{
p = append_str (p, _T(", GOYES "));
p = append_r_addr (p, &pc, disp, 2, 3);
}
else
p = append_str (p, _T(", RTNYES"));
break;
case CLASS_MNEMONICS:
p = append_str (out, (disp == 0) ? _T("rt") : _T("b"));
p = append_str (p, (fn == 6) ? _T("bc") : _T("bs"));
p = append_tab (out);
wsprintf (buf, _T("#%d, st"), n);
p = append_str (p, buf);
if (disp != 0)
{
p = append_str (p, _T(", "));
p = append_r_addr (p, &pc, disp, 2, 3);
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 8:
case 9:
n = read_nibble (addr);
pc = *addr;
disp = read_int (addr, 2);
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, _T("?P%c"), (fn == 8) ? _T('#') : _T('='));
p = append_str (out, buf);
p = append_tab (out);
wsprintf (buf, _T("%d"), n);
p = append_str (p, buf);
if (disp != 0)
{
p = append_str (p, _T(", GOYES "));
p = append_r_addr (p, &pc, disp, 2, 3);
}
else
p = append_str (p, _T(", RTNYES"));
break;
case CLASS_MNEMONICS:
p = append_str (out, (disp == 0) ? _T("rt") : _T("b"));
p = append_str (p, (fn == 8) ? _T("ne.1") : _T("eq.1"));
p = append_tab (out);
wsprintf (buf, _T("#%d, p"), n);
p = append_str (p, buf);
if (disp != 0)
{
p = append_str (p, _T(", "));
p = append_r_addr (p, &pc, disp, 2, 3);
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 0xc:
case 0xe:
pc = *addr;
if (fn == 0xe)
pc += 4;
disp = read_int (addr, 4);
switch (disassembler_mode)
{
case HP_MNEMONICS:
p = append_str (out, (fn == 0xc) ? _T("GOLONG") : _T("GOSUBL"));
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6);
break;
case CLASS_MNEMONICS:
p = append_str (out, (fn == 0xc) ? _T("bra.4") : _T("bsr.4"));
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 4, (fn == 0xc) ? 2 : 6);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 0xd:
case 0xf:
pc = read_int (addr, 5);
switch (disassembler_mode)
{
case HP_MNEMONICS:
p = append_str (out, (fn == 0xd) ? _T("GOVLNG") : _T("GOSBVL"));
p = append_tab (out);
p = append_addr (p, pc);
break;
case CLASS_MNEMONICS:
p = append_str (out, (fn == 0xd) ? _T("jmp") : _T("jsr"));
p = append_tab (out);
p = append_addr (p, pc);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
default:
break;
}
return p;
}
// public functions
DWORD disassemble (DWORD addr, LPTSTR out)
{
BYTE n;
BYTE fn;
LPTSTR p = out;
TCHAR c;
TCHAR buf[20];
DWORD disp, pc;
switch (n = read_nibble (&addr))
{
case 0:
if ((n = read_nibble (&addr)) != 0xe)
{
p = append_str (out, opcode_0_tbl[n + 16 * disassembler_mode]);
break;
}
fn = read_nibble (&addr);
n = read_nibble (&addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
wsprintf (buf, op_str_0[(n & 7) + 8 * HP_MNEMONICS],
(n < 8) ? _T('&') : _T('!'));
p = append_str (out, buf);
p = append_tab (out);
p = append_field (p, fn);
break;
case CLASS_MNEMONICS:
p = append_str (out, (n < 8) ? _T("and") : _T("or"));
p = append_field (p, fn);
p = append_tab (out);
p = append_str (p, op_str_0[(n & 7) + 8 * CLASS_MNEMONICS]);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 1:
p = disasm_1 (&addr, out);
break;
case 2:
n = read_nibble (&addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
p = append_str (out, _T("P="));
p = append_tab (out);
wsprintf (buf, _T("%d"), n);
p = append_str (p, buf);
break;
case CLASS_MNEMONICS:
wsprintf (buf, _T("move.1 #%d, p"), n);
p = append_str (out, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 3:
fn = read_nibble (&addr);
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (fn < 5)
{
wsprintf (buf, _T("LC(%d)"), fn + 1);
}
else
{
wsprintf (buf, _T("LCHEX"));
}
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, &addr, fn + 1);
break;
case CLASS_MNEMONICS:
wsprintf (buf, _T("move.%d"), fn + 1);
p = append_str (out, buf);
p = append_tab (out);
p = append_imm_nibble (p, &addr, fn + 1);
wsprintf (buf, _T(", c.p"));
p = append_str (p, buf);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 4:
case 5:
pc = addr;
disp = read_int (&addr, 2);
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (disp == 2)
{
p = append_str (out, _T("NOP3"));
break;
}
wsprintf (buf, (disp == 0) ? _T("RTN%sC") : _T("GO%sC"), (n == 4) ? _T("") : _T("N"));
p = append_str (out, buf);
if (disp != 0)
{
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 2, 1);
}
break;
case CLASS_MNEMONICS:
if (disp == 2)
{
p = append_str (out, _T("nop3"));
break;
}
p = append_str (out, (disp == 0) ? _T("rtc") : _T("bc"));
p = append_str (p, (n == 4) ? _T("s") : _T("c"));
if (disp != 0)
{
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 2, 1);
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 6:
pc = addr;
disp = read_int (&addr, 3); // read GOTO distance
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (disp == 3) // special case "GOTO next instruction"
{
p = append_str (out, _T("NOP4"));
break;
}
if (disp == 4) // special case "GOTO to +4 nibbles"
{
addr++; // skipping the fifth nibble in the opcode
p = append_str (out, _T("NOP5"));
break;
}
p = append_str (out, _T("GOTO"));
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 3, 1);
break;
case CLASS_MNEMONICS:
if (disp == 3)
{
p = append_str (out, _T("nop4"));
break;
}
if (disp == 4)
{
addr++; // skipping the fifth nibble in the opcode
p = append_str (out, _T("nop5"));
break;
}
p = append_str (out, _T("bra.3"));
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 3, 1);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 7:
pc = addr + 3;
disp = read_int (&addr, 3);
switch (disassembler_mode)
{
case HP_MNEMONICS:
p = append_str (out, _T("GOSUB"));
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 3, 4);
break;
case CLASS_MNEMONICS:
p = append_str (out, _T("bsr.3"));
p = append_tab (out);
p = append_r_addr (p, &pc, disp, 3, 4);
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
case 8:
fn = read_nibble (&addr); /* PEEK */
--addr;
if (fn != 0xa && fn != 0xb)
{
p = disasm_8 (&addr, out);
break;
}
/* Fall through */
case 9:
fn = read_nibble (&addr);
if (n == 8)
{
c = (TCHAR) ((fn == 0xa) ? 0 : 1);
fn = 0xf;
}
else
{
c = (TCHAR) ((fn < 8) ? 0 : 1);
fn &= 7;
}
n = read_nibble (&addr);
pc = addr;
disp = read_int (&addr, 2);
switch (disassembler_mode)
{
case HP_MNEMONICS:
if ((c == 0) && (n >= 8))
wsprintf (buf, op_str_9[(n & 3) + 8 * HP_MNEMONICS + 4],
in_str_9[((n >> 2) & 3) + 4 * c + 8 * HP_MNEMONICS]);
else
wsprintf (buf, op_str_9[(n & 3) + 8 * HP_MNEMONICS],
in_str_9[((n >> 2) & 3) + 4 * c + 8 * HP_MNEMONICS]);
p = append_str (out, buf);
p = append_tab (out);
p = append_field (p, fn);
p = append_str (p, _T(", "));
p = append_str (p, (disp == 0) ? _T("RTNYES") : _T("GOYES "));
if (disp != 0)
{
p = append_r_addr (p, &pc, disp, 2, 3);
}
break;
case CLASS_MNEMONICS:
p = append_str (out, (disp == 0) ? _T("rt") : _T("b"));
p = append_str (p, in_str_9[((n >> 2) & 3) + 4 * c + 8 * CLASS_MNEMONICS]);
p = append_field (p, fn);
p = append_tab (out);
if ((c == 0) && (n >= 8))
p = append_str (p, op_str_9[(n & 3) + 8 * CLASS_MNEMONICS + 4]);
else
p = append_str (p, op_str_9[(n & 3) + 8 * CLASS_MNEMONICS]);
if (disp != 0)
{
p = append_str (p, _T(", "));
p = append_r_addr (p, &pc, disp, 2, 3);
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
break;
}
break;
default:
switch (n)
{
case 0xa:
fn = read_nibble (&addr);
c = (TCHAR) ((fn < 8) ? 0 : 1);
fn &= 7;
disp = 0xa;
break;
case 0xb:
fn = read_nibble (&addr);
c = (TCHAR) ((fn < 8) ? 0 : 1);
fn &= 7;
disp = 0xb;
break;
case 0xc:
case 0xd:
fn = 0xf;
c = (TCHAR) (n & 1);
disp = 0xa;
break;
case 0xe:
case 0xf:
fn = 0xf;
c = (TCHAR) (n & 1);
disp = 0xb;
break;
default:
fn = 0;
disp = 0;
c = 0;
break;
}
n = read_nibble (&addr);
pc = 0;
switch (disp)
{
case 0xa:
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (c == 0)
{
if (n < 0xc)
{
p = _T("+");
}
else
{
p = _T("%c=%c-1");
pc = 2;
}
}
else
{
if (n < 4)
{
p = _T("%c=0");
pc = 1;
}
else
if (n >= 0xc)
{
p = _T("%c%cEX");
pc = 3;
}
else
{
p = _T("%c=%c");
pc = 3;
}
}
break;
case CLASS_MNEMONICS:
if (c == 0)
{
if (n < 0xc)
{
p = _T("add");
}
else
{
p = _T("dec");
pc = 1;
}
}
else
{
if (n < 4)
{
p = _T("clr");
pc = 1;
}
else
if (n >= 0xc)
{
p = _T("exg");
}
else
{
p = _T("move");
if (n < 8)
n -= 4;
}
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
return addr;
}
break;
case 0xb:
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (c == 0)
{
if (n >= 0xc)
{
p = _T("-");
}
else
if ((n >= 4) && (n <= 7))
{
p = _T("%c=%c+1");
pc = 2;
n -= 4;
}
else
{
p = _T("-");
}
}
else
{
if (n < 4)
{
p = _T("%cSL");
pc = 1;
}
else
if (n < 8)
{
p = _T("%cSR");
pc = 1;
}
else
if (n < 0xc)
{
p = _T("%c=-%c");
pc = 2;
}
else
{
p = _T("%c=-%c-1");
pc = 2;
}
}
break;
case CLASS_MNEMONICS:
if (c == 0)
{
if (n >= 0xc)
{
p = _T("subr");
}
else
if ((n >= 4) && (n <= 7))
{
p = _T("inc");
pc = 1;
n -= 4;
}
else
{
p = _T("sub");
}
}
else
{
pc = 1;
if (n < 4)
{
p = _T("lsl");
}
else
if (n < 8)
{
p = _T("lsr");
}
else
if (n < 0xc)
{
p = _T("neg");
}
else
{
p = _T("not");
}
}
break;
default:
p = append_str (out, _T("Unknown disassembler mode"));
return addr;
}
break;
}
switch (disassembler_mode)
{
case HP_MNEMONICS:
if (pc == 0)
{
wsprintf (buf, op_str_af[n + 16 * HP_MNEMONICS], p);
}
else
if (pc == 1)
{
wsprintf (buf, p, (n & 3) + _T('A'));
}
else
if (pc == 2)
{
wsprintf (buf, p, (n & 3) + _T('A'), (n & 3) + _T('A'));
}
else
{
wsprintf (buf, p, hp_reg_1_af[n], hp_reg_2_af[n]);
}
p = append_str (out, buf);
p = append_tab (out);
p = append_field (p, fn);
break;
case CLASS_MNEMONICS:
p = append_str (out, p);
p = append_field (p, fn);
p = append_tab (out);
if (pc == 1)
{
wsprintf (buf, _T("%c"), (n & 3) + _T('a'));
p = append_str (p, buf);
}
else
{
p = append_str (p, op_str_af[n + 16 * CLASS_MNEMONICS]);
}
break;
default:
p = append_str (p, _T("Unknown disassembler mode"));
break;
}
break;
}
*p = 0;
return addr;
}