/*
 *   Disasm.c
 *
 *   This file is part of Emu28, a ported version of x48
 *
 *   Copyright (C) 2002 Christoph Gießelink
 *
 */
#include "pch.h"
#include "Emu28.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"),
	_T("INTON"), NULL, NULL, NULL,			// 1LK7
	NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL,
//	_T("PC=(A)"), _T("BUSCD"), _T("PC=(C)"), _T("INTOFF"),
	_T("PC=(A)"), NULL, NULL, _T("INTOFF"),	// 1LK7
	/*
	 * Class Mnemonics
	 */
//	_T("inton"), NULL, NULL, _T("buscb"),
	_T("inton"), NULL, NULL, NULL,			// 1LK7
	NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, NULL,
//	_T("jmp     (a)"), _T("buscd"), _T("jmp     (c)"), _T("intoff")
	_T("jmp     (a)"), NULL, NULL, _T("intoff") // 1LK7
};

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;
					}
					p = out;		// for 1LK7
					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:
							break;			// 1LK7
							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:
							break;			// 1LK7
							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:
							break;			// 1LK7
							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:
					break;					// 1LK7
					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:
					break;					// 1LK7
					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:
					break;					// 1LK7
					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:
					break;					// 1LK7
					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;
}
