// license:BSD-3-Clause
// copyright-holders:Peter Trauner,Antoine Mine
/*****************************************************************************
 *
 *   saturnds.c
 *   portable saturn emulator interface
 *   (hp calculators)
 *
 *****************************************************************************/

#include "emu.h"
#include "debugger.h"

#include "saturn.h"

#define SATURN_HP_MNEMONICS

#if defined SATURN_HP_MNEMONICS
// class/hp mnemonics
static int set=0;
#else
// readable/normal mnemonics
static int set=1;
#endif

#define P "P"
#define WP "WP"
#define XS "XS"
#define X "X"
#define S "S"
#define M "M"
#define B "B"
#define W "W"
#define A "A"

static const char *const adr_b[]=
{ P, WP, XS, X, S, M, B, W };

static const char *const adr_af[]=
{ P, WP, XS, X, S, M, B, W, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, A };

static const char *const adr_a[]=
	{ P, WP, XS, X, S, M, B, W };

static const char number_2_hex[]=
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };

#define SATURN_PEEKOP_DIS8(v)   v = (INT8)( oprom[pos] | ( oprom[pos+1] << 4 ) ); pos+= 2;

#define SATURN_PEEKOP_DIS12(v)  v = oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ); \
								pos += 3;                                                       \
								if ( v & 0x0800 )   v = -0x1000 + v;

#define SATURN_PEEKOP_DIS16(v)  v = (INT16)( oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ) | ( oprom[pos+3] << 12 ) ); pos += 4;

#define SATURN_PEEKOP_ADR(v)    v = oprom[pos] | ( oprom[pos+1] << 4 ) | ( oprom[pos+2] << 8 ) | ( oprom[pos+3] << 12 ) | ( oprom[pos+4] << 16 ); pos += 5;


// don't split branch and return, source relies on this ordering
enum MNEMONICS
{
	Return, ReturnSetXM, ReturnSetCarry, ReturnClearCarry, ReturnFromInterrupt,
	jump3,jump4,jump,
	call3,call4,call,
	branchCarrySet, returnCarrySet,
	branchCarryClear, returnCarryClear,

	outCS, outC, inA, inC,
	unconfig, config, Cid, shutdown, cp1, reset, buscc,
	CcopyP, PcopyC, sreq, CswapP,

	inton, AloadImm, buscb,
	clearAbit, setAbit,
	branchAbitclear, returnAbitclear,
	branchAbitset, returnAbitset,
	clearCbit, setCbit,
	branchCbitclear, returnCbitclear,
	branchCbitset, returnCbitset,
	PCloadA, buscd, PCloadC, intoff, rsi,

	jumpA, jumpC, PCcopyA, PCcopyC, AcopyPC, CcopyPC,

	clearHST,
	branchHSTclear, returnHSTclear,

	clearBitST, setBitST,
	branchSTclear, returnSTclear,
	branchSTset, returnSTset,


	branchPdiffers, returnPdiffers,
	branchPequals, returnPequals,

	branchAequalsB, returnAequalsB,
	branchBequalsC, returnBequalsC,
	branchAequalsC, returnAequalsC,
	branchCequalsD, returnCequalsD,
	branchAdiffersB, returnAdiffersB,
	branchBdiffersC, returnBdiffersC,
	branchAdiffersC, returnAdiffersC,
	branchCdiffersD, returnCdiffersD,
	branchAzero, returnAzero,
	branchBzero, returnBzero,
	branchCzero, returnCzero,
	branchDzero, returnDzero,
	branchAnotzero, returnAnotzero,
	branchBnotzero, returnBnotzero,
	branchCnotzero, returnCnotzero,
	branchDnotzero, returnDnotzero,

	branchAgreaterB, returnAgreaterB,
	branchBgreaterC, returnBgreaterC,
	branchCgreaterA, returnCgreaterA,
	branchDgreaterC, returnDgreaterC,
	branchAlowerB, returnAlowerB,
	branchBlowerC, returnBlowerC,
	branchClowerA, returnClowerA,
	branchDlowerC, returnDlowerC,
	branchAnotlowerB, returnAnotlowerB,
	branchBnotlowerC, returnBnotlowerC,
	branchCnotlowerA, returnCnotlowerA,
	branchDnotlowerC, returnDnotlowerC,
	branchAnotgreaterB, returnAnotgreaterB,
	branchBnotgreaterC, returnBnotgreaterC,
	branchCnotgreaterA, returnCnotgreaterA,
	branchDnotgreaterC, returnDnotgreaterC,

	SetHexMode, SetDecMode,
	PushC, PopC,

	D0loadImm2, D0loadImm4, D0loadImm5,
	D1loadImm2, D1loadImm4, D1loadImm5,
	PloadImm, CloadImm,

	clearST,
	CcopyST, STcopyC,
	swapCST,

	incP, decP,

	R0copyA, R1copyA, R2copyA, R3copyA, R4copyA,
	R0copyC, R1copyC, R2copyC, R3copyC, R4copyC,

	AcopyR0, AcopyR1, AcopyR2, AcopyR3, AcopyR4,
	CcopyR0, CcopyR1, CcopyR2, CcopyR3, CcopyR4,

	D0copyA, D1copyA, D0copyC, D1copyC,
	D0copyAShort, D1copyAShort, D0copyCShort, D1copyCShort, // other class mnemonic

	SwapAR0, SwapAR1, SwapAR2, SwapAR3, SwapAR4,
	SwapCR0, SwapCR1, SwapCR2, SwapCR3, SwapCR4,

	SwapAD0, SwapAD1, SwapCD0, SwapCD1,
	SwapAD0Short, SwapAD1Short, SwapCD0Short, SwapCD1Short, // other class mnemonic

	D0storeA, D1storeA, D0storeC, D1storeC,
	AloadD0, AloadD1, CloadD0, CloadD1,

	D0addImm, D1addImm, D0subImm, D1subImm,
	AaddImm, BaddImm, CaddImm, DaddImm,
	AsubImm, BsubImm, CsubImm, DsubImm,

	AandB, BandC, CandA, DandC, BandA, CandB, AandC, CandD,
	AorB, BorC, CorA, DorC, BorA, CorB, AorC, CorD,

	Ashiftrightbit, Bshiftrightbit, Cshiftrightbit, Dshiftrightbit,

	AshiftleftCarry, BshiftleftCarry, CshiftleftCarry, DshiftleftCarry,
	AshiftrightCarry, BshiftrightCarry, CshiftrightCarry, DshiftrightCarry,

	AaddB, BaddC, CaddA, DaddC, AaddA, BaddB, CaddC, DaddD,
	BaddA, CaddB, AaddC, CaddD, decA, decB, decC, decD,

	AsubB, BsubC, CsubA, DsubC, incA, incB, incC, incD,
	BsubA, CsubB, AsubC, CsubD, AsubnB, BsubnC, CsubnA, DsubnC,

	clearA, clearB, clearC, clearD,
	AcopyB, BcopyC, CcopyA, DcopyC, BcopyA, CcopyB, AcopyC, CcopyD,
	AswapB, BswapC, CswapA, DswapC,

	Ashiftleft, Bshiftleft, Cshiftleft, Dshiftleft,
	Ashiftright, Bshiftright, Cshiftright, Dshiftright,
	negateA, negateB, negateC, negateD,
	notA, notB, notC, notD

};

static const struct {
	const char *name[2];
} mnemonics[]={
	{ { "rtn",                  "RET" } },
	{ { "rtnsXM",               "RETSETXM" } },
	{ { "rtnsC",                "RETSETC" } },
	{ { "rtncC",                "RETCLRC" } },
	{ { "rti",                  "RETI" } },
	{ { "goto    %05x",         "JUMP.3   %05x" } },
	{ { "goto    %05x",         "JUMP.4   %05x" } },
	{ { "goto    %05x",         "JUMP     %05x" } },
	{ { "gosub   %05x",         "CALL.3   %05x" } },
	{ { "gosub   %05x",         "CALL.4   %05x" } },
	{ { "gosub   %05x",         "CALL     %05x" } },
	{ { "goC     %05x",         "BRCS     %05x" } },
	{ { "rtnC",                 "RETCS" } },
	{ { "gonC    %05x",         "BRCC     %05x" } },
	{ { "rtnnC",                "RETCC" } },

	{ { "OUT=CS",               "OUT.S    C" } },
	{ { "OUT=C",                "OUT.X    C" } },
	{ { "A=IN",                 "IN.4     A" } },
	{ { "C=IN",                 "IN.4     C" } },
	{ { "uncnfg",               "UNCNFG" } },
	{ { "config",               "CONFIG" } },
	{ { "C=id",                 "MOVE.A   ID,C" } },
	{ { "!shutdn",              "!SHUTDN" } },
	{ { "C+P+1",                "ADD.A    P+1,C" } },
	{ { "reset",                "RESET" } },
	{ { "!buscc",               "!BUSCC" } },
	{ { "C=P     %x",           "MOVE.1   P,C,%x" } },
	{ { "P=C     %x",           "MOVE.1   C,%x,P" } },
	{ { "!sreq?",               "!SREQ" } },
	{ { "CPex    %x",           "SWAP.1   P,C,%x" } },

	{ { "!inton",               "!INTON" } },
	{ { "LA %-2x   %s",         "MOVE.P%-2x %s,A" } },
	{ { "!buscb",               "!BUSCB" } },
	{ { "Abit=0  %x",           "CLRB     %x,A" } },
	{ { "Abit=1  %x",           "SETB     %x,A" } },
	{ { "?Abit=0 %x,%05x",      "BRBC     %x,A,%05x" } },
	{ { "?Abit=0 %x,rtn",       "RETBC    %x,A" } },
	{ { "?Abit=1 %x,%05x",      "BRBS     %x,A,%05x" } },
	{ { "?Abit=1 %x,rtn",       "RETBS    %x,A" } },
	{ { "Cbit=0  %x",           "CLRB     %x,C" } },
	{ { "Cbit=1  %x",           "SETB     %x,C" } },
	{ { "?Cbit=0 %x,%05x",      "BRBC     %x,C,%05x" } },
	{ { "?Cbit=0 %x,rtn",       "RETBC    %x,C" } },
	{ { "?Cbit=1 %x,%05x",      "BRBS     %x,C,%05x" } },
	{ { "?Cbit=1 %x,rtn",       "RETBS    %x,C" } },
	{ { "PC=(A)",               "JUMP.A   @A" } },
	{ { "!buscd",               "!BUSCD" } },
	{ { "PC=(C)",               "JUMP.A   @C" } },
	{ { "!intoff",              "!INTOFF" } },
	{ { "!rsi",                 "!RSI" } },

	{ { "PC=A",                 "JUMP.A   A" } },
	{ { "PC=C",                 "JUMP.A   C" } },
	{ { "A=PC",                 "MOVE.A   PC,A" } },
	{ { "C=PC",                 "MOVE.A   PC,C" } },
	{ { "APCex",                "SWAP.A   A,PC" } },
	{ { "CPCex",                "SWAP.A   C,PC" } },

	{ { "HST=0   %x",           "CLRHST   %x" } },
	{ { "?HST=0  %x,%05x",      "BRBCHST  %x,%05x" } },
	{ { "?HST=0  %x,rtn",           "RETBCHST %x" } },
	{ { "ST=0    %x",           "CLRB     %x,ST" } },
	{ { "ST=1    %x",           "SETB     %x,ST" } },
	{ { "?ST=0   %x,%05x",      "BRBC     ST,%x,%05x" } },
	{ { "?ST=0   %x,rtn",           "RETBC    ST,%x" } },
	{ { "?ST=1   %x,%05x",      "BRBS     ST,%x,%05x" } },
	{ { "?ST=1   %x,rtn",           "RETBS    ST,%x" } },
	{ { "?P#     %x,%05x",      "BRNE     P,%x,%05x" } },
	{ { "?P#     %x,rtn",           "RETNE    P,%x" } },
	{ { "?P=     %x,%05x",      "BREQ     P,%x,%05x" } },
	{ { "?P=     %x,rtn",           "RETEQ    P,%x" } },

	{ { "?A=B    %s,%05x",      "BREQ.%-2s  A,B,%05x" } },
	{ { "?A=B    %s,rtn",           "RETEQ.%-2s A,B" } },
	{ { "?B=C    %s,%05x",      "BREQ.%-2s  B,C,%05x" } },
	{ { "?B=C    %s,rtn",           "RETEQ.%-2s B,C" } },
	{ { "?A=C    %s,%05x",      "BREQ.%-2s  A,C,%05x" } },
	{ { "?A=C    %s,rtn",           "RETEQ.%-2s A,C" } },
	{ { "?C=D    %s,%05x",      "BREQ.%-2s  C,D,%05x" } },
	{ { "?C=D    %s,rtn",           "RETEQ.%-2s C,D" } },
	{ { "?A#B    %s,%05x",      "BRNE.%-2s  A,B,%05x" } },
	{ { "?A#B    %s,rtn",           "RETNE.%-2s A,B" } },
	{ { "?B#C    %s,%05x",      "BRNE.%-2s  B,C,%05x" } },
	{ { "?B#C    %s,rtn",           "RETNE.%-2s B,C" } },
	{ { "?A#C    %s,%05x",      "BRNE.%-2s  A,C,%05x" } },
	{ { "?A#C    %s,rtn",           "RETNE.%-2s A,C" } },
	{ { "?C#D    %s,%05x",      "BRNE.%-2s  C,D,%05x" } },
	{ { "?C#D    %s,rtn",           "RETNE.%-2s C,D" } },
	{ { "?A=0    %s,%05x",      "BRZ.%-2s   A,%05x" } },
	{ { "?A=0    %s,rtn",           "RETZ.%-2s  A" } },
	{ { "?B=0    %s,%05x",      "BRZ.%-2s   B,%05x" } },
	{ { "?B=0    %s,rtn",           "RETZ.%-2s  B" } },
	{ { "?C=0    %s,%05x",      "BRZ.%-2s   C,%05x" } },
	{ { "?C=0    %s,rtn",           "RETZ.%-2s  C" } },
	{ { "?D=0    %s,%05x",      "BRZ.%-2s   D,%05x" } },
	{ { "?D=0    %s,rtn",           "RETZ.%-2s  D" } },
	{ { "?A#0    %s,%05x",      "BRNZ.%-2s  A,%05x" } },
	{ { "?A#0    %s,rtn",           "RETNZ.%-2s A" } },
	{ { "?B#0    %s,%05x",      "BRNZ.%-2s  B,%05x" } },
	{ { "?B#0    %s,rtn",           "RETNZ.%-2s B" } },
	{ { "?C#0    %s,%05x",      "BRNZ.%-2s  C,%05x" } },
	{ { "?C#0    %s,rtn",           "RETNZ.%-2s C" } },
	{ { "?D#0    %s,%05x",      "BRNZ.%-2s  D,%05x" } },
	{ { "?D#0    %s,rtn",           "RETNZ.%-2s D" } },

	{ { "?A>B    %s,%05x",      "BRGT.%-2s  A,B,%05x" } },
	{ { "?A>B    %s,rtn",           "RETGT.%-2s A,B" } },
	{ { "?B>C    %s,%05x",      "BRGT.%-2s  B,C,%05x" } },
	{ { "?B>C    %s,rtn",           "RETGT.%-2s B,C" } },
	{ { "?C>A    %s,%05x",      "BRGT.%-2s  C,A,%05x" } },
	{ { "?C>A    %s,rtn",           "RETGT.%-2s C,A" } },
	{ { "?D>C    %s,%05x",      "BRGT.%-2s  D,C,%05x" } },
	{ { "?D>C    %s,rtn",           "RETGT.%-2s D,C" } },
	{ { "?A<B    %s,%05x",      "BRLT.%-2s  A,B,%05x" } },
	{ { "?A<B    %s,rtn",           "RETLT.%-2s A,B" } },
	{ { "?B<C    %s,%05x",      "BRLT.%-2s  B,C,%05x" } },
	{ { "?B<C    %s,rtn",           "RETLT.%-2s B,C" } },
	{ { "?C<A    %s,%05x",      "BRLT.%-2s  C,A,%05x" } },
	{ { "?C<A    %s,rtn",           "RETLT.%-2s C,A" } },
	{ { "?D<C    %s,%05x",      "BRLT.%-2s  D,C,%05x" } },
	{ { "?D<C    %s,rtn",           "RETLT.%-2s D,C" } },
	{ { "?A>=B   %s,%05x",      "BRGE.%-2s  A,B,%05x" } },
	{ { "?A>=B   %s,rtn",           "RETGE.%-2s A,B" } },
	{ { "?B>=C   %s,%05x",      "BRGE.%-2s  B,C,%05x" } },
	{ { "?B>=C   %s,rtn",           "RETGE.%-2s B,C" } },
	{ { "?C>=A   %s,%05x",      "BRGE.%-2s  C,A,%05x" } },
	{ { "?C>=A   %s,rtn",           "RETGE.%-2s C,A" } },
	{ { "?D>=C   %s,%05x",      "BRGE.%-2s  D,C,%05x" } },
	{ { "?D>=C   %s,rtn",           "RETGE.%-2s D,C" } },
	{ { "?A<=B   %s,%05x",      "BRLE.%-2s  A,B,%05x" } },
	{ { "?A<=B   %s,rtn",           "RETLE.%-2s A,B" } },
	{ { "?B<=C   %s,%05x",      "BRLE.%-2s  B,C,%05x" } },
	{ { "?B<=C   %s,rtn",           "RETLE.%-2s B,C" } },
	{ { "?C<=A   %s,%05x",      "BRLE.%-2s  C,A,%05x" } },
	{ { "?C<=A   %s,rtn",           "RETLE.%-2s C,A" } },
	{ { "?D<=C   %s,%05x",      "BRLE.%-2s  D,C,%05x" } },
	{ { "?D<=C   %s,rtn",           "RETLE.%-2s D,C" } },

	{ { "sethex",               "SETHEX" } },
	{ { "setdec",               "SETDEC" } },
	{ { "RSTK=C",               "PUSH.A   C" } },
	{ { "C=RSTK",               "POP.A    C" } },

	// load immediate
	{ { "D0=     %02x",         "MOVE.2   %02x,D0" } },
	{ { "D0=     %04x",         "MOVE.4   %04x,D0" } },
	{ { "D0=     %05x",         "MOVE.5   %05x,D0" } },

	{ { "D1=     %02x",         "MOVE.2   %02x,D1" } },
	{ { "D1=     %04x",         "MOVE.4   %04x,D1" } },
	{ { "D1=     %05x",         "MOVE.5   %05x,D1" } },

	{ { "P=      %x",           "MOVE     %x,P" } },
	{ { "lC %-2x   %s",         "MOVE.P%-2x %s,C" } },

	{ { "clrST",                "CLR.X    ST" } },
	{ { "C=ST",                 "MOVE.X   ST,C" } },
	{ { "ST=C",                 "MOVE.X   C,ST" } },
	{ { "CSTex",                "SWAP.X   C,ST" } },

	{ { "P=P+1",                "INC      P" } },
	{ { "P=P-1",                "DEC      P" } },

	// copy
	{ { "R0=A    %s",           "MOVE.%-2s  A,R0" } },
	{ { "R1=A    %s",           "MOVE.%-2s  A,R1" } },
	{ { "R2=A    %s",           "MOVE.%-2s  A,R2" } },
	{ { "R3=A    %s",           "MOVE.%-2s  A,R3" } },
	{ { "R4=A    %s",           "MOVE.%-2s  A,R4" } },

	{ { "R0=C    %s",           "MOVE.%-2s  C,R0" } },
	{ { "R1=C    %s",           "MOVE.%-2s  C,R1" } },
	{ { "R2=C    %s",           "MOVE.%-2s  C,R2" } },
	{ { "R3=C    %s",           "MOVE.%-2s  C,R3" } },
	{ { "R4=C    %s",           "MOVE.%-2s  C,R4" } },

	{ { "A=R0    %s",           "MOVE.%-2s  R0,A" } },
	{ { "A=R1    %s",           "MOVE.%-2s  R1,A" } },
	{ { "A=R2    %s",           "MOVE.%-2s  R2,A" } },
	{ { "A=R3    %s",           "MOVE.%-2s  R3,A" } },
	{ { "A=R4    %s",           "MOVE.%-2s  R4,A" } },

	{ { "C=R0    %s",           "MOVE.%-2s  R0,C" } },
	{ { "C=R1    %s",           "MOVE.%-2s  R1,C" } },
	{ { "C=R2    %s",           "MOVE.%-2s  R2,C" } },
	{ { "C=R3    %s",           "MOVE.%-2s  R3,C" } },
	{ { "C=R4    %s",           "MOVE.%-2s  R4,C" } },

	{ { "D0=A",                 "MOVE.A   A,D0" } },
	{ { "D1=A",                 "MOVE.A   A,D1" } },
	{ { "D0=C",                 "MOVE.A   C,D0" } },
	{ { "D1=C",                 "MOVE.A   C,D1" } },
	{ { "D0=As",                "MOVE.S   A,D0" } },
	{ { "D1=As",                "MOVE.S   A,D1" } },
	{ { "D0=Cs",                "MOVE.S   C,D0" } },
	{ { "D1=Cs",                "MOVE.S   C,D1" } },

	// swap operations
	{ { "AR0ex   %s",           "SWAP.%-2s  A,R0" } },
	{ { "AR1ex   %s",           "SWAP.%-2s  A,R1" } },
	{ { "AR2ex   %s",           "SWAP.%-2s  A,R2" } },
	{ { "AR3ex   %s",           "SWAP.%-2s  A,R3" } },
	{ { "AR4ex   %s",           "SWAP.%-2s  A,R4" } },

	{ { "CR0ex   %s",           "SWAP.%-2s  C,R0" } },
	{ { "CR1ex   %s",           "SWAP.%-2s  C,R1" } },
	{ { "CR2ex   %s",           "SWAP.%-2s  C,R2" } },
	{ { "CR3ex   %s",           "SWAP.%-2s  C,R3" } },
	{ { "CR4ex   %s",           "SWAP.%-2s  C,R4" } },

	{ { "AD0ex",                "SWAP.A   A,D0" } },
	{ { "AD1ex",                "SWAP.A   A,D1" } },
	{ { "CD0ex",                "SWAP.A   C,D0" } },
	{ { "CD1ex",                "SWAP.A   C,D1" } },
	{ { "AD0xs",                "SWAP.S   A,D0" } },
	{ { "AD1xs",                "SWAP.S   A,D1" } },
	{ { "CD0xs",                "SWAP.S   C,D0" } },
	{ { "CD1xs",                "SWAP.S   C,D1" } },

	// store
	{ { "Dat0=A  %s",           "MOVE.%-2s  A,@D0" } },
	{ { "Dat1=A  %s",           "MOVE.%-2s  A,@D0" } },
	{ { "Dat0=C  %s",           "MOVE.%-2s  C,@D0" } },
	{ { "Dat1=C  %s",           "MOVE.%-2s  C,@D0" } },

	// load
	{ { "A=Dat0  %s",           "MOVE.%-2s  @D0,A" } },
	{ { "A=Dat1  %s",           "MOVE.%-2s  @D0,A" } },
	{ { "C=Dat0  %s",           "MOVE.%-2s  @D0,C" } },
	{ { "C=Dat1  %s",           "MOVE.%-2s  @D0,C" } },

	// add/sub immediate
	{ { "D0=D0+  %x",           "ADD.A    %x,D0" } },
	{ { "D1=D1+  %x",           "ADD.A    %x,D1" } },
	{ { "D0=D0-  %x",           "SUB.A    %x,D0" } },
	{ { "D1=D1-  %x",           "SUB.A    %x,D1" } },

	{ { "A=A+    %s,%x",        "ADD.%-2s   %x,A" } },
	{ { "B=B+    %s,%x",        "ADD.%-2s   %x,B" } },
	{ { "C=C+    %s,%x",        "ADD.%-2s   %x,C" } },
	{ { "D=D+    %s,%x",        "ADD.%-2s   %x,D" } },
	{ { "A=A-    %s,%x",        "SUB.%-2s   %x,A" } },
	{ { "B=B-    %s,%x",        "SUB.%-2s   %x,B" } },
	{ { "C=C-    %s,%x",        "SUB.%-2s   %x,C" } },
	{ { "D=D-    %s,%x",        "SUB.%-2s   %x,D" } },

	{ { "A=A&B   %s",           "AND.%-2s   B,A" } },
	{ { "B=B&C   %s",           "AND.%-2s   C,B" } },
	{ { "C=C&A   %s",           "AND.%-2s   A,C" } },
	{ { "D=D&C   %s",           "AND.%-2s   C,D" } },
	{ { "B=B&A   %s",           "AND.%-2s   A,B" } },
	{ { "C=C&B   %s",           "AND.%-2s   B,C" } },
	{ { "A=A&C   %s",           "AND.%-2s   C,A" } },
	{ { "C=C&D   %s",           "AND.%-2s   D,C" } },

	{ { "A=A!B   %s",           "OR.%-2s    B,A" } },
	{ { "B=B!C   %s",           "OR.%-2s    C,B" } },
	{ { "C=C!A   %s",           "OR.%-2s    A,C" } },
	{ { "D=D!C   %s",           "OR.%-2s    C,D" } },
	{ { "B=B!A   %s",           "OR.%-2s    A,B" } },
	{ { "C=C!B   %s",           "OR.%-2s    B,C" } },
	{ { "A=A!C   %s",           "OR.%-2s    C,A" } },
	{ { "C=C!D   %s",           "OR.%-2s    D,C" } },

	{ { "Asrb    %s",           "SRB.%-2s   A" } },
	{ { "Bsrb    %s",           "SRB.%-2s   B" } },
	{ { "Csrb    %s",           "SRB.%-2s   C" } },
	{ { "Dsrb    %s",           "SRB.%-2s   D" } },

	{ { "Aslc    %s",           "RLN.%-2s   A" } },
	{ { "Bslc    %s",           "RLN.%-2s   B" } },
	{ { "Cslc    %s",           "RLN.%-2s   C" } },
	{ { "Dslc    %s",           "RLN.%-2s   D" } },
	{ { "Asrc    %s",           "RRN.%-2s   A" } },
	{ { "Bsrc    %s",           "RRN.%-2s   B" } },
	{ { "Csrc    %s",           "RRN.%-2s   C" } },
	{ { "Dsrc    %s",           "RRN.%-2s   D" } },

	{ { "A=A+B   %s",           "ADD.%-2s   B,A" } },
	{ { "B=B+C   %s",           "ADD.%-2s   C,B" } },
	{ { "C=C+A   %s",           "ADD.%-2s   A,C" } },
	{ { "D=D+C   %s",           "ADD.%-2s   C,D" } },
	{ { "A=A+A   %s",           "ADD.%-2s   A,A" } },
	{ { "B=B+B   %s",           "ADD.%-2s   B,B" } },
	{ { "C=C+C   %s",           "ADD.%-2s   C,C" } },
	{ { "D=D+C   %s",           "ADD.%-2s   D,D" } },
	{ { "B=B+A   %s",           "ADD.%-2s   A,B" } },
	{ { "C=C+B   %s",           "ADD.%-2s   B,C" } },
	{ { "A=A+C   %s",           "ADD.%-2s   C,A" } },
	{ { "C=C+D   %s",           "ADD.%-2s   D,C" } },
	{ { "A=A-1   %s",           "DEC.%-2s   A" } },
	{ { "B=B-1   %s",           "DEC.%-2s   B" } },
	{ { "C=C-1   %s",           "DEC.%-2s   C" } },
	{ { "D=D-1   %s",           "DEC.%-2s   D" } },

	{ { "A=A-B   %s",           "ADD.%-2s   B,A" } },
	{ { "B=B-C   %s",           "ADD.%-2s   C,B" } },
	{ { "C=C-A   %s",           "ADD.%-2s   A,C" } },
	{ { "D=D-C   %s",           "ADD.%-2s   C,D" } },
	{ { "A=A+1   %s",           "INC.%-2s   A" } },
	{ { "B=B+1   %s",           "INC.%-2s   B" } },
	{ { "C=C+1   %s",           "INC.%-2s   C" } },
	{ { "D=D+1   %s",           "INC.%-2s   D" } },
	{ { "B=B-A   %s",           "SUB.%-2s   A,B" } },
	{ { "C=C-B   %s",           "SUB.%-2s   B,C" } },
	{ { "A=A-C   %s",           "SUB.%-2s   C,A" } },
	{ { "C=C-D   %s",           "SUB.%-2s   D,C" } },
	{ { "A=B-A   %s",           "SUBN.%-2s  B,A" } },
	{ { "B=C-B   %s",           "SUBN.%-2s  C,B" } },
	{ { "C=A-C   %s",           "SUBN.%-2s  A,C" } },
	{ { "D=C-D   %s",           "SUBN.%-2s  C,D" } },

	{ { "A=0     %s",           "CLR.%-2s   A" } },
	{ { "B=0     %s",           "CLR.%-2s   B" } },
	{ { "C=0     %s",           "CLR.%-2s   C" } },
	{ { "D=0     %s",           "CLR.%-2s   D" } },
	{ { "A=B     %s",           "MOVE.%-2s  B,A" } },
	{ { "B=C     %s",           "MOVE.%-2s  C,B" } },
	{ { "C=A     %s",           "MOVE.%-2s  A,C" } },
	{ { "D=C     %s",           "MOVE.%-2s  C,D" } },
	{ { "B=A     %s",           "MOVE.%-2s  A,B" } },
	{ { "C=B     %s",           "MOVE.%-2s  B,C" } },
	{ { "A=C     %s",           "MOVE.%-2s  C,A" } },
	{ { "C=D     %s",           "MOVE.%-2s  D,C" } },
	{ { "ABex    %s",           "SWAP.%-2s  A,B" } },
	{ { "BCex    %s",           "SWAP.%-2s  B,C" } },
	{ { "ACex    %s",           "SWAP.%-2s  A,C" } },
	{ { "CDex    %s",           "SWAP.%-2s  C,D" } },

	{ { "Asl     %s",           "SLN.%-2s   A" } },
	{ { "Bsl     %s",           "SLN.%-2s   B" } },
	{ { "Csl     %s",           "SLN.%-2s   C" } },
	{ { "Dsl     %s",           "SLN.%-2s   D" } },
	{ { "Asr     %s",           "SRN.%-2s   A" } },
	{ { "Bsr     %s",           "SRN.%-2s   B" } },
	{ { "Csr     %s",           "SRN.%-2s   C" } },
	{ { "Dsr     %s",           "SRN.%-2s   D" } },
	{ { "A=-A    %s",           "NEG.%-2s   A" } },
	{ { "B=-B    %s",           "NEG.%-2s   B" } },
	{ { "C=-C    %s",           "NEG.%-2s   C" } },
	{ { "D=-D    %s",           "NEG.%-2s   D" } },
	{ { "A=-A-1  %s",           "NOT.%-2s   A" } },
	{ { "B=-B-1  %s",           "NOT.%-2s   B" } },
	{ { "C=-C-1  %s",           "NOT.%-2s   C" } },
	{ { "D=-D-1  %s",           "NOT.%-2s   D" } }

};

enum opcode_sel
{
	Complete=-1,
	Illegal,
	Opcode0, Opcode0E, Opcode0Ea,
	Opcode1, Opcode10, Opcode11, Opcode12, Opcode13, Opcode14, Opcode15,
	Opcode8, Opcode80, Opcode808, Opcode8081,
	Opcode81, Opcode818, Opcode818a, Opcode819, Opcode819a,
	Opcode81A, Opcode81Aa, Opcode81Aa0,Opcode81Aa1, Opcode81Aa2, Opcode81B,
	Opcode8A, Opcode8B,
	Opcode9, Opcode9a, Opcode9b,
	OpcodeA, OpcodeAa, OpcodeAb,
	OpcodeB, OpcodeBa, OpcodeBb,
	OpcodeC,
	OpcodeD,
	OpcodeE,
	OpcodeF
};

enum opcode_adr
{
	AdrNone,
	AdrAF, AdrA, AdrB, AdrCount,
	BranchReturn, TestBranchRet, ImmBranch,
	ABranchReturn, // address field A
	xBranchReturn, // address field specified in previous opcode entry
	Imm, ImmCount, ImmCload, Imm2, Imm4, Imm5,
	Dis3, Dis3Call, Dis4, Dis4Call, Abs,
	FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW, FieldA,
	AdrImmCount
};

struct OPCODE
{
	opcode_sel sel;
	opcode_adr adr;
	MNEMONICS mnemonic;
};

static const char *field_2_string(int adr_enum)
{
	switch (adr_enum) {
	case FieldP: return P;
	case FieldWP: return WP;
	case FieldXS: return XS;
	case FieldX: return X;
	case FieldS: return S;
	case FieldM: return M;
	case FieldB: return B;
	case FieldW: return W;
	case FieldA: return A;
	}
	return nullptr;
}

static const OPCODE opcodes[][0x10]= {
	{
		// first digit
		{ Opcode0 },
		{ Opcode1 },
		{ Complete,     Imm,            PloadImm },
		{ Complete,     ImmCload,       CloadImm },
		{ Complete,     BranchReturn,   branchCarrySet},
		{ Complete,     BranchReturn,   branchCarryClear },
		{ Complete,     Dis3,           jump3 },
		{ Complete,     Dis3Call,       call3 },
		{ Opcode8 },
		{ Opcode9 },
		{ OpcodeA },
		{ OpcodeB },
		{ OpcodeC },
		{ OpcodeD },
		{ OpcodeE },
		{ OpcodeF }
	}, { // 0
		{ Complete,     AdrNone,        ReturnSetXM },
		{ Complete,     AdrNone,        Return },
		{ Complete,     AdrNone,        ReturnSetCarry },
		{ Complete,     AdrNone,        ReturnClearCarry },
		{ Complete,     AdrNone,        SetHexMode },
		{ Complete,     AdrNone,        SetDecMode },
		{ Complete,     AdrNone,        PushC },
		{ Complete,     AdrNone,        PopC },
		{ Complete,     AdrNone,        clearST },
		{ Complete,     AdrNone,        CcopyST },
		{ Complete,     AdrNone,        STcopyC },
		{ Complete,     AdrNone,        swapCST },
		{ Complete,     AdrNone,        incP },
		{ Complete,     AdrNone,        decP },
		{ Opcode0E },
		{ Complete,     AdrNone,        ReturnFromInterrupt }
	}, { //0E
		{ Opcode0Ea,    AdrAF },
		{ Opcode0Ea,    AdrAF },
		{ Opcode0Ea,    AdrAF },
		{ Opcode0Ea,    AdrAF },
		{ Opcode0Ea,    AdrAF },
		{ Opcode0Ea,    AdrAF },
		{ Opcode0Ea,    AdrAF },
		{ Opcode0Ea,    AdrAF },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Opcode0Ea,    AdrAF }
	}, { //0Ea
		{ Complete,     AdrNone,        AandB },
		{ Complete,     AdrNone,        BandC },
		{ Complete,     AdrNone,        CandA },
		{ Complete,     AdrNone,        DandC },
		{ Complete,     AdrNone,        BandA },
		{ Complete,     AdrNone,        CandB },
		{ Complete,     AdrNone,        AandC },
		{ Complete,     AdrNone,        CandD },
		{ Complete,     AdrNone,        AorB },
		{ Complete,     AdrNone,        BorC },
		{ Complete,     AdrNone,        CorA },
		{ Complete,     AdrNone,        DorC },
		{ Complete,     AdrNone,        BorA },
		{ Complete,     AdrNone,        CorB },
		{ Complete,     AdrNone,        AorC },
		{ Complete,     AdrNone,        CorD }
	}, { //1
		{ Opcode10 },
		{ Opcode11 },
		{ Opcode12 },
		{ Opcode13 },
		{ Opcode14 },
		{ Opcode15 },
		{ Complete,     ImmCount,       D0addImm },
		{ Complete,     ImmCount,       D1addImm },
		{ Complete,     ImmCount,       D0subImm },
		{ Complete,     Imm2,           D0loadImm2 },
		{ Complete,     Imm4,           D0loadImm4 },
		{ Complete,     Imm5,           D0loadImm5 },
		{ Complete,     ImmCount,       D1subImm },
		{ Complete,     Imm2,           D1loadImm2 },
		{ Complete,     Imm4,           D1loadImm4 },
		{ Complete,     Imm5,           D1loadImm5 }
	}, { //10
		{ Complete,     FieldW,         R0copyA },
		{ Complete,     FieldW,         R1copyA },
		{ Complete,     FieldW,         R2copyA },
		{ Complete,     FieldW,         R3copyA },
		{ Complete,     FieldW,         R4copyA },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Complete,     FieldW,         R0copyC },
		{ Complete,     FieldW,         R1copyC },
		{ Complete,     FieldW,         R2copyC },
		{ Complete,     FieldW,         R3copyC },
		{ Complete,     FieldW,         R4copyC },
		{ Illegal },
		{ Illegal },
		{ Illegal }
	}, { //11
		{ Complete,     FieldW,         AcopyR0 },
		{ Complete,     FieldW,         AcopyR1 },
		{ Complete,     FieldW,         AcopyR2 },
		{ Complete,     FieldW,         AcopyR3 },
		{ Complete,     FieldW,         AcopyR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Complete,     FieldW,         CcopyR0 },
		{ Complete,     FieldW,         CcopyR1 },
		{ Complete,     FieldW,         CcopyR2 },
		{ Complete,     FieldW,         CcopyR3 },
		{ Complete,     FieldW,         CcopyR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal }
	}, { //12
		{ Complete,     FieldW,         SwapAR0 },
		{ Complete,     FieldW,         SwapAR1 },
		{ Complete,     FieldW,         SwapAR2 },
		{ Complete,     FieldW,         SwapAR3 },
		{ Complete,     FieldW,         SwapAR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Complete,     FieldW,         SwapCR0 },
		{ Complete,     FieldW,         SwapCR1 },
		{ Complete,     FieldW,         SwapCR2 },
		{ Complete,     FieldW,         SwapCR3 },
		{ Complete,     FieldW,         SwapCR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal }
	}, { //13
		{ Complete,     FieldA,         D0copyA },
		{ Complete,     FieldA,         D1copyA },
		{ Complete,     FieldA,         SwapAD0 },
		{ Complete,     FieldA,         SwapAD1 },
		{ Complete,     FieldA,         D0copyC },
		{ Complete,     FieldA,         D1copyC },
		{ Complete,     FieldA,         SwapCD0 },
		{ Complete,     FieldA,         SwapCD1 },
		{ Complete,     FieldS,         D0copyAShort },
		{ Complete,     FieldS,         D1copyAShort },
		{ Complete,     FieldS,         SwapAD0Short },
		{ Complete,     FieldS,         SwapAD1Short },
		{ Complete,     FieldS,         D0copyCShort },
		{ Complete,     FieldS,         D1copyCShort },
		{ Complete,     FieldS,         SwapCD0Short },
		{ Complete,     FieldS,         SwapCD1Short }
	}, { //14
		{ Complete,     FieldA,         D0storeA },
		{ Complete,     FieldA,         D1storeA },
		{ Complete,     FieldA,         AloadD0 },
		{ Complete,     FieldA,         AloadD1 },
		{ Complete,     FieldA,         D0storeC },
		{ Complete,     FieldA,         D1storeC },
		{ Complete,     FieldA,         CloadD0 },
		{ Complete,     FieldA,         CloadD1 },
		{ Complete,     FieldB,         D0storeA },
		{ Complete,     FieldB,         D1storeA },
		{ Complete,     FieldB,         AloadD0 },
		{ Complete,     FieldB,         AloadD1 },
		{ Complete,     FieldB,         D0storeC },
		{ Complete,     FieldB,         D1storeC },
		{ Complete,     FieldB,         CloadD0 },
		{ Complete,     FieldB,         CloadD1 }
	}, { //15
		{ Complete,     AdrA,           D0storeA },
		{ Complete,     AdrA,           D1storeA },
		{ Complete,     AdrA,           AloadD0 },
		{ Complete,     AdrA,           AloadD1 },
		{ Complete,     AdrA,           D0storeC },
		{ Complete,     AdrA,           D1storeC },
		{ Complete,     AdrA,           CloadD0 },
		{ Complete,     AdrA,           CloadD1 },
		{ Complete,     AdrCount,       D0storeA },
		{ Complete,     AdrCount,       D1storeA },
		{ Complete,     AdrCount,       AloadD0 },
		{ Complete,     AdrCount,       AloadD1 },
		{ Complete,     AdrCount,       D0storeC },
		{ Complete,     AdrCount,       D1storeC },
		{ Complete,     AdrCount,       CloadD0 },
		{ Complete,     AdrCount,       CloadD1 },
	}, { //8
		{ Opcode80 },
		{ Opcode81 },
		{ Complete,     Imm,            clearHST },
		{ Complete,     TestBranchRet,  branchHSTclear },
		{ Complete,     Imm,            clearBitST },
		{ Complete,     Imm,            setBitST },
		{ Complete,     TestBranchRet,  branchSTclear },
		{ Complete,     TestBranchRet,  branchSTset },
		{ Complete,     TestBranchRet,  branchPdiffers},
		{ Complete,     TestBranchRet,  branchPequals},
		{ Opcode8A },
		{ Opcode8B },
		{ Complete,     Dis4,           jump4 },
		{ Complete,     Abs,            jump },
		{ Complete,     Dis4Call,       call4 },
		{ Complete,     Abs,            call }
	}, { //80
		{ Complete,     AdrNone,        outCS },
		{ Complete,     AdrNone,        outC },
		{ Complete,     AdrNone,        inA },
		{ Complete,     AdrNone,        inC },
		{ Complete,     AdrNone,        unconfig },
		{ Complete,     AdrNone,        config },
		{ Complete,     AdrNone,        Cid },
		{ Complete,     AdrNone,        shutdown },
		{ Opcode808 },
		{ Complete,     AdrNone,        cp1 },
		{ Complete,     AdrNone,        reset },
		{ Complete,     AdrNone,        buscc },
		{ Complete,     Imm,            CcopyP },
		{ Complete,     Imm,            PcopyC },
		{ Complete,     AdrNone,        sreq },
		{ Complete,     Imm,            CswapP }
	}, { //808
		{ Complete,     AdrNone,        inton },
		{ Opcode8081 },
		{ Complete,     ImmCload,       AloadImm },
		{ Complete,     AdrNone,        buscb },
		{ Complete,     Imm,            clearAbit },
		{ Complete,     Imm,            setAbit },
		{ Complete,     TestBranchRet,      branchAbitclear },
		{ Complete,     TestBranchRet,      branchAbitset },
		{ Complete,     Imm,            clearCbit },
		{ Complete,     Imm,            setCbit },
		{ Complete,     TestBranchRet,      branchCbitclear },
		{ Complete,     TestBranchRet,      branchCbitset },
		{ Complete,     AdrNone,        PCloadA },
		{ Complete,     AdrNone,        buscd },
		{ Complete,     AdrNone,        PCloadC },
		{ Complete,     AdrNone,        intoff }
	}, { //8081
		{ Complete,     AdrNone,        rsi },
		//! rest illegal
	}, { //81
		{ Complete,     FieldW,         AshiftleftCarry },
		{ Complete,     FieldW,         BshiftleftCarry },
		{ Complete,     FieldW,         CshiftleftCarry },
		{ Complete,     FieldW,         DshiftleftCarry },
		{ Complete,     FieldW,         AshiftrightCarry },
		{ Complete,     FieldW,         BshiftrightCarry },
		{ Complete,     FieldW,         CshiftrightCarry },
		{ Complete,     FieldW,         DshiftrightCarry },
		{ Opcode818 },
		{ Opcode819 },
		{ Opcode81A },
		{ Opcode81B },
		{ Complete,     FieldW,         Ashiftrightbit },
		{ Complete,     FieldW,         Bshiftrightbit },
		{ Complete,     FieldW,         Cshiftrightbit },
		{ Complete,     FieldW,         Dshiftrightbit }
	}, { //818
		{ Opcode818a,   AdrAF },
		{ Opcode818a,   AdrAF },
		{ Opcode818a,   AdrAF },
		{ Opcode818a,   AdrAF },
		{ Opcode818a,   AdrAF },
		{ Opcode818a,   AdrAF },
		{ Opcode818a,   AdrAF },
		{ Opcode818a,   AdrAF },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Opcode818a,   AdrAF },
	}, { //818a
		{ Complete,     AdrImmCount,        AaddImm },
		{ Complete,     AdrImmCount,        BaddImm },
		{ Complete,     AdrImmCount,            CaddImm },
		{ Complete,     AdrImmCount,        DaddImm },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Complete,     AdrImmCount,        AsubImm },
		{ Complete,     AdrImmCount,        BsubImm },
		{ Complete,     AdrImmCount,        CsubImm },
		{ Complete,     AdrImmCount,        DsubImm },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
	}, { //819
		{ Opcode819a,   AdrAF },
		{ Opcode819a,   AdrAF },
		{ Opcode819a,   AdrAF },
		{ Opcode819a,   AdrAF },
		{ Opcode819a,   AdrAF },
		{ Opcode819a,   AdrAF },
		{ Opcode819a,   AdrAF },
		{ Opcode819a,   AdrAF }, //?
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Opcode819a,   AdrAF },
	}, { //819a }
		{ Complete,     AdrNone,        Ashiftright },
		{ Complete,     AdrNone,        Bshiftright },
		{ Complete,     AdrNone,        Cshiftright },
		{ Complete,     AdrNone,        Dshiftright },
		//! rest illegal
	}, { //81A
		{ Opcode81Aa,   AdrAF },
		{ Opcode81Aa,   AdrAF },
		{ Opcode81Aa,   AdrAF },
		{ Opcode81Aa,   AdrAF },
		{ Opcode81Aa,   AdrAF },
		{ Opcode81Aa,   AdrAF },
		{ Opcode81Aa,   AdrAF },
		{ Opcode81Aa,   AdrAF },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Opcode81Aa,   AdrAF },
	}, { //81Aa
		{ Opcode81Aa0 },
		{ Opcode81Aa1 },
		{ Opcode81Aa2 },
		//! rest illegal
	}, { //81Aa0
		{ Complete,     AdrNone,        R0copyA },
		{ Complete,     AdrNone,        R1copyA },
		{ Complete,     AdrNone,        R2copyA },
		{ Complete,     AdrNone,        R3copyA },
		{ Complete,     AdrNone,        R4copyA },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Complete,     AdrNone,        R0copyC },
		{ Complete,     AdrNone,        R1copyC },
		{ Complete,     AdrNone,        R2copyC },
		{ Complete,     AdrNone,        R3copyC },
		{ Complete,     AdrNone,        R4copyC },
		{ Illegal },
		{ Illegal },
		{ Illegal }
	}, { //81Aa1
		{ Complete,     AdrNone,        AcopyR0 },
		{ Complete,     AdrNone,        AcopyR1 },
		{ Complete,     AdrNone,        AcopyR2 },
		{ Complete,     AdrNone,        AcopyR3 },
		{ Complete,     AdrNone,        AcopyR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Complete,     AdrNone,        CcopyR0 },
		{ Complete,     AdrNone,        CcopyR1 },
		{ Complete,     AdrNone,        CcopyR2 },
		{ Complete,     AdrNone,        CcopyR3 },
		{ Complete,     AdrNone,        CcopyR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal }
	}, { //81Aa2
		{ Complete,     AdrNone,        SwapAR0 },
		{ Complete,     AdrNone,        SwapAR1 },
		{ Complete,     AdrNone,        SwapAR2 },
		{ Complete,     AdrNone,        SwapAR3 },
		{ Complete,     AdrNone,        SwapAR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Complete,     AdrNone,        SwapCR0 },
		{ Complete,     AdrNone,        SwapCR1 },
		{ Complete,     AdrNone,        SwapCR2 },
		{ Complete,     AdrNone,        SwapCR3 },
		{ Complete,     AdrNone,        SwapCR4 },
		{ Illegal },
		{ Illegal },
		{ Illegal }
	}, { //81B
		{ Illegal },
		{ Illegal },
		{ Complete,     AdrNone,        jumpA },
		{ Complete,     AdrNone,        jumpC },
		{ Complete,     AdrNone,        PCcopyA },
		{ Complete,     AdrNone,        PCcopyC },
		{ Complete,     AdrNone,        AcopyPC },
		{ Complete,     AdrNone,        CcopyPC },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal },
		{ Illegal }
	}, { //8A
		{ Complete,     ABranchReturn,  branchAequalsB },
		{ Complete,     ABranchReturn,  branchBequalsC },
		{ Complete,     ABranchReturn,  branchAequalsC },
		{ Complete,     ABranchReturn,  branchCequalsD },
		{ Complete,     ABranchReturn,  branchAdiffersB },
		{ Complete,     ABranchReturn,  branchBdiffersC },
		{ Complete,     ABranchReturn,  branchAdiffersC },
		{ Complete,     ABranchReturn,  branchCdiffersD },
		{ Complete,     ABranchReturn,  branchAzero },
		{ Complete,     ABranchReturn,  branchBzero },
		{ Complete,     ABranchReturn,  branchCzero },
		{ Complete,     ABranchReturn,  branchDzero },
		{ Complete,     ABranchReturn,  branchAnotzero },
		{ Complete,     ABranchReturn,  branchBnotzero },
		{ Complete,     ABranchReturn,  branchCnotzero },
		{ Complete,     ABranchReturn,  branchDnotzero }
	}, { //8B
		{ Complete,     ABranchReturn,  branchAgreaterB },
		{ Complete,     ABranchReturn,  branchBgreaterC },
		{ Complete,     ABranchReturn,  branchCgreaterA },
		{ Complete,     ABranchReturn,  branchDgreaterC },
		{ Complete,     ABranchReturn,  branchAlowerB },
		{ Complete,     ABranchReturn,  branchBlowerC },
		{ Complete,     ABranchReturn,  branchClowerA },
		{ Complete,     ABranchReturn,  branchDlowerC },
		{ Complete,     ABranchReturn,  branchAnotlowerB },
		{ Complete,     ABranchReturn,  branchBnotlowerC },
		{ Complete,     ABranchReturn,  branchCnotlowerA },
		{ Complete,     ABranchReturn,  branchDnotlowerC },
		{ Complete,     ABranchReturn,  branchAnotgreaterB },
		{ Complete,     ABranchReturn,  branchBnotgreaterC },
		{ Complete,     ABranchReturn,  branchCnotgreaterA },
		{ Complete,     ABranchReturn,  branchDnotgreaterC }
	}, { //9
		{ Opcode9a,     AdrA },
		{ Opcode9a,     AdrA },
		{ Opcode9a,     AdrA },
		{ Opcode9a,     AdrA },
		{ Opcode9a,     AdrA },
		{ Opcode9a,     AdrA },
		{ Opcode9a,     AdrA },
		{ Opcode9a,     AdrA },
		{ Opcode9b,     AdrB },
		{ Opcode9b,     AdrB },
		{ Opcode9b,     AdrB },
		{ Opcode9b,     AdrB },
		{ Opcode9b,     AdrB },
		{ Opcode9b,     AdrB },
		{ Opcode9b,     AdrB },
		{ Opcode9b,     AdrB },
	}, { //9a
		{ Complete,     xBranchReturn,  branchAequalsB },
		{ Complete,     xBranchReturn,  branchBequalsC },
		{ Complete,     xBranchReturn,  branchAequalsC },
		{ Complete,     xBranchReturn,  branchCequalsD },
		{ Complete,     xBranchReturn,  branchAdiffersB },
		{ Complete,     xBranchReturn,  branchBdiffersC },
		{ Complete,     xBranchReturn,  branchAdiffersC },
		{ Complete,     xBranchReturn,  branchCdiffersD },
		{ Complete,     xBranchReturn,  branchAzero },
		{ Complete,     xBranchReturn,  branchBzero },
		{ Complete,     xBranchReturn,  branchCzero },
		{ Complete,     xBranchReturn,  branchDzero },
		{ Complete,     xBranchReturn,  branchAnotzero },
		{ Complete,     xBranchReturn,  branchBnotzero },
		{ Complete,     xBranchReturn,  branchCnotzero },
		{ Complete,     xBranchReturn,  branchDnotzero }
	}, { //9b
		{ Complete,     xBranchReturn,  branchAgreaterB },
		{ Complete,     xBranchReturn,  branchBgreaterC },
		{ Complete,     xBranchReturn,  branchCgreaterA },
		{ Complete,     xBranchReturn,  branchDgreaterC },
		{ Complete,     xBranchReturn,  branchAlowerB },
		{ Complete,     xBranchReturn,  branchBlowerC },
		{ Complete,     xBranchReturn,  branchClowerA },
		{ Complete,     xBranchReturn,  branchDlowerC },
		{ Complete,     xBranchReturn,  branchAnotlowerB },
		{ Complete,     xBranchReturn,  branchBnotlowerC },
		{ Complete,     xBranchReturn,  branchCnotlowerA },
		{ Complete,     xBranchReturn,  branchDnotlowerC },
		{ Complete,     xBranchReturn,  branchAnotgreaterB },
		{ Complete,     xBranchReturn,  branchBnotgreaterC },
		{ Complete,     xBranchReturn,  branchCnotgreaterA },
		{ Complete,     xBranchReturn,  branchDnotgreaterC }
	}, { //A
		{ OpcodeAa,     AdrA },
		{ OpcodeAa,     AdrA },
		{ OpcodeAa,     AdrA },
		{ OpcodeAa,     AdrA },
		{ OpcodeAa,     AdrA },
		{ OpcodeAa,     AdrA },
		{ OpcodeAa,     AdrA },
		{ OpcodeAa,     AdrA },
		{ OpcodeAb,     AdrB },
		{ OpcodeAb,     AdrB },
		{ OpcodeAb,     AdrB },
		{ OpcodeAb,     AdrB },
		{ OpcodeAb,     AdrB },
		{ OpcodeAb,     AdrB },
		{ OpcodeAb,     AdrB },
		{ OpcodeAb,     AdrB },
	}, { //Aa
		{ Complete,     AdrNone,        AaddB },
		{ Complete,     AdrNone,        BaddC },
		{ Complete,     AdrNone,        CaddA },
		{ Complete,     AdrNone,        DaddC },
		{ Complete,     AdrNone,        AaddA },
		{ Complete,     AdrNone,        BaddB },
		{ Complete,     AdrNone,        CaddC },
		{ Complete,     AdrNone,        DaddD },
		{ Complete,     AdrNone,        BaddA },
		{ Complete,     AdrNone,        CaddB },
		{ Complete,     AdrNone,        AaddC },
		{ Complete,     AdrNone,        CaddD },
		{ Complete,     AdrNone,        decA },
		{ Complete,     AdrNone,        decB },
		{ Complete,     AdrNone,        decC },
		{ Complete,     AdrNone,        decD },
	}, { //Ab
		{ Complete,     AdrNone,        clearA },
		{ Complete,     AdrNone,        clearB },
		{ Complete,     AdrNone,        clearC },
		{ Complete,     AdrNone,        clearD },
		{ Complete,     AdrNone,        AcopyB },
		{ Complete,     AdrNone,        BcopyC },
		{ Complete,     AdrNone,        CcopyA },
		{ Complete,     AdrNone,        DcopyC },
		{ Complete,     AdrNone,        BcopyA },
		{ Complete,     AdrNone,        CcopyB },
		{ Complete,     AdrNone,        AcopyC },
		{ Complete,     AdrNone,        CcopyD },
		{ Complete,     AdrNone,        AswapB },
		{ Complete,     AdrNone,        BswapC },
		{ Complete,     AdrNone,        CswapA },
		{ Complete,     AdrNone,        DswapC }
	}, { //B
		{ OpcodeBa,     AdrA },
		{ OpcodeBa,     AdrA },
		{ OpcodeBa,     AdrA },
		{ OpcodeBa,     AdrA },
		{ OpcodeBa,     AdrA },
		{ OpcodeBa,     AdrA },
		{ OpcodeBa,     AdrA },
		{ OpcodeBa,     AdrA },
		{ OpcodeBb,     AdrB },
		{ OpcodeBb,     AdrB },
		{ OpcodeBb,     AdrB },
		{ OpcodeBb,     AdrB },
		{ OpcodeBb,     AdrB },
		{ OpcodeBb,     AdrB },
		{ OpcodeBb,     AdrB },
		{ OpcodeBb,     AdrB },
	}, { //Ba
		{ Complete,     AdrNone,        AsubB },
		{ Complete,     AdrNone,        BsubC },
		{ Complete,     AdrNone,        CsubA },
		{ Complete,     AdrNone,        DsubC },
		{ Complete,     AdrNone,        incA },
		{ Complete,     AdrNone,        incB },
		{ Complete,     AdrNone,        incC },
		{ Complete,     AdrNone,        incD },
		{ Complete,     AdrNone,        BsubA },
		{ Complete,     AdrNone,        CsubB },
		{ Complete,     AdrNone,        AsubC },
		{ Complete,     AdrNone,        CsubD },
		{ Complete,     AdrNone,        AsubnB },
		{ Complete,     AdrNone,        BsubnC },
		{ Complete,     AdrNone,        CsubnA },
		{ Complete,     AdrNone,        DsubnC },
	}, { //Bb
		{ Complete,     AdrNone,        Ashiftleft },
		{ Complete,     AdrNone,        Bshiftleft },
		{ Complete,     AdrNone,        Cshiftleft },
		{ Complete,     AdrNone,        Dshiftleft },
		{ Complete,     AdrNone,        Ashiftright },
		{ Complete,     AdrNone,        Bshiftright },
		{ Complete,     AdrNone,        Cshiftright },
		{ Complete,     AdrNone,        Dshiftright },
		{ Complete,     AdrNone,        negateA },
		{ Complete,     AdrNone,        negateB },
		{ Complete,     AdrNone,        negateC },
		{ Complete,     AdrNone,        negateD },
		{ Complete,     AdrNone,        notA },
		{ Complete,     AdrNone,        notB },
		{ Complete,     AdrNone,        notC },
		{ Complete,     AdrNone,        notD }
	}, { //C
		{ Complete,     FieldA,     AaddB },
		{ Complete,     FieldA,     BaddC },
		{ Complete,     FieldA,     CaddA },
		{ Complete,     FieldA,     DaddC },
		{ Complete,     FieldA,     AaddA },
		{ Complete,     FieldA,     BaddB },
		{ Complete,     FieldA,     CaddC },
		{ Complete,     FieldA,     DaddD },
		{ Complete,     FieldA,     BaddA },
		{ Complete,     FieldA,     CaddB },
		{ Complete,     FieldA,     AaddC },
		{ Complete,     FieldA,     CaddD },
		{ Complete,     FieldA,     decA },
		{ Complete,     FieldA,     decB },
		{ Complete,     FieldA,     decC },
		{ Complete,     FieldA,     decD }
	}, { //D
		{ Complete,     FieldA,     clearA },
		{ Complete,     FieldA,     clearB },
		{ Complete,     FieldA,     clearC },
		{ Complete,     FieldA,     clearD },
		{ Complete,     FieldA,     AcopyB },
		{ Complete,     FieldA,     BcopyC },
		{ Complete,     FieldA,     CcopyA },
		{ Complete,     FieldA,     DcopyC },
		{ Complete,     FieldA,     BcopyA },
		{ Complete,     FieldA,     CcopyB },
		{ Complete,     FieldA,     AcopyC },
		{ Complete,     FieldA,     CcopyD },
		{ Complete,     FieldA,     AswapB },
		{ Complete,     FieldA,     BswapC },
		{ Complete,     FieldA,     CswapA },
		{ Complete,     FieldA,     DswapC }
	}, { //E
		{ Complete,     FieldA,     AsubB },
		{ Complete,     FieldA,     BsubC },
		{ Complete,     FieldA,     CsubA },
		{ Complete,     FieldA,     DsubC },
		{ Complete,     FieldA,     incA },
		{ Complete,     FieldA,     incB },
		{ Complete,     FieldA,     incC },
		{ Complete,     FieldA,     incD },
		{ Complete,     FieldA,     BsubA },
		{ Complete,     FieldA,     CsubB },
		{ Complete,     FieldA,     AsubC },
		{ Complete,     FieldA,     CsubD },
		{ Complete,     FieldA,     AsubnB },
		{ Complete,     FieldA,     BsubnC },
		{ Complete,     FieldA,     CsubnA },
		{ Complete,     FieldA,     DsubnC }
	}, { //F
		{ Complete,     FieldA,     Ashiftleft },
		{ Complete,     FieldA,     Bshiftleft },
		{ Complete,     FieldA,     Cshiftleft },
		{ Complete,     FieldA,     Dshiftleft },
		{ Complete,     FieldA,     Ashiftright },
		{ Complete,     FieldA,     Bshiftright },
		{ Complete,     FieldA,     Cshiftright },
		{ Complete,     FieldA,     Dshiftright },
		{ Complete,     FieldA,     negateA },
		{ Complete,     FieldA,     negateB },
		{ Complete,     FieldA,     negateC },
		{ Complete,     FieldA,     negateD },
		{ Complete,     FieldA,     notA },
		{ Complete,     FieldA,     notB },
		{ Complete,     FieldA,     notC },
		{ Complete,     FieldA,     notD }
	}
};

static const int field_adr_af[]=
{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW, 0, 0, 0, 0, 0, 0, 0, FieldA };

static const int field_adr_a[]=
{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW};

static const int field_adr_b[]=
{ FieldP, FieldWP, FieldXS, FieldX, FieldS, FieldM, FieldB, FieldW };

CPU_DISASSEMBLE( saturn )
{
	int adr=0;

	int cont=1; // operation still not complete disassembled
	char bin[10]; int binsize=0; // protocollizing fetched nibbles
	char number[17];
	const OPCODE *level=opcodes[0]; //pointer to current digit
	int op; // currently fetched nibble
	int pos = 0;

	int i,c,v;

	while (cont)
	{
		op = oprom[pos++] & 0xf;
		level+=op;
		switch (level->sel) {
		case Illegal:
			cont=0;
			bin[binsize++]=number_2_hex[op];
			bin[binsize]=0;
			sprintf(buffer, "???%s",bin);
			break;
		default:
			bin[binsize++]=number_2_hex[op];
			switch (level->adr) {
			case AdrNone: break;
			case AdrA:
				adr=field_adr_a[op];
				break;
			case AdrAF:
				adr=field_adr_af[op];
				break;
			case AdrB:
				adr=field_adr_b[op&7];
				break;
			default:
				cont = 0;
				bin[binsize++]=number_2_hex[op];
				bin[binsize]=0;
				sprintf(buffer, "???%s",bin);
				break;
			}
			break;
		case Complete:
			cont=0;
			switch (level->adr==AdrNone?adr:level->adr) {
			case AdrNone:
				strcpy(buffer, mnemonics[level->mnemonic].name[set]);
				break;
			case Imm:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], oprom[pos++]);
				break;
			case ImmCount:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], oprom[pos++]+1);
				break;
			case AdrImmCount:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], field_2_string(adr), oprom[pos++]+1);
				break;
			case AdrCount: // mnemonics have string %s for address field
				snprintf(number,sizeof(number),"%x",oprom[pos++]+1);
				sprintf(buffer, mnemonics[level->mnemonic].name[set], number);
				break;
			case Imm2:
				v=oprom[pos++];
				v|=oprom[pos++]<<4;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], v);
				break;
			case Imm4:
				v=oprom[pos++];
				v|=oprom[pos++]<<4;
				v|=oprom[pos++]<<8;
				v|=oprom[pos++]<<12;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], v);
				break;
			case Imm5:
				v=oprom[pos++];
				v|=oprom[pos++]<<4;
				v|=oprom[pos++]<<8;
				v|=oprom[pos++]<<12;
				v|=oprom[pos++]<<16;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], v);
				break;
			case ImmCload:
				c=i=oprom[pos++] & 0xf;
				number[i+1]=0;
				for (;i>=0; i--) number[i]=number_2_hex[oprom[pos++] & 0xf];
				sprintf(buffer, mnemonics[level->mnemonic].name[set], c+1, number);
				break;
			case Dis3:
				SATURN_PEEKOP_DIS12(v);
				c=(pc+pos-3+v)&0xfffff;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], c );
				break;
			case Dis3Call:
				SATURN_PEEKOP_DIS12(v);
				c=(pc+pos+v)&0xfffff;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], c );
				break;
			case Dis4:
				SATURN_PEEKOP_DIS16(v);
				c=(pc+pos-4+v)&0xfffff;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], c );
				break;
			case Dis4Call:
				SATURN_PEEKOP_DIS16(v);
				c=(pc+pos+v)&0xfffff;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], c );
				break;
			case Abs:
				SATURN_PEEKOP_ADR(v);
				sprintf(buffer, mnemonics[level->mnemonic].name[set], v );
				break;
			case BranchReturn:
				SATURN_PEEKOP_DIS8(v);
				if (v==0) {
					strcpy(buffer, mnemonics[level->mnemonic+1].name[set]);
				} else {
					c=(pc+pos-2+v)&0xfffff;
					sprintf(buffer, mnemonics[level->mnemonic].name[set], c);
				}
				break;
			case ABranchReturn:
				SATURN_PEEKOP_DIS8(v);
				if (v==0) {
					sprintf(buffer, mnemonics[level->mnemonic+1].name[set], A);
				} else {
					c=(pc+pos-2+v)&0xfffff;
					sprintf(buffer, mnemonics[level->mnemonic].name[set], A, c);
				}
				break;
			case xBranchReturn:
				SATURN_PEEKOP_DIS8(v);
				if (v==0) {
					sprintf(buffer, mnemonics[level->mnemonic+1].name[set], field_2_string(adr));
				} else {
					c=(pc+pos-2+v)&0xfffff;
					sprintf(buffer, mnemonics[level->mnemonic].name[set], field_2_string(adr), c);
				}
				break;
			case TestBranchRet:
				i=oprom[pos++];
				SATURN_PEEKOP_DIS8(v);
				if (v==0) {
					sprintf(buffer, mnemonics[level->mnemonic+1].name[set], i);
				} else {
					c=(pc+pos-2+v)&0xfffff;
					sprintf(buffer, mnemonics[level->mnemonic].name[set], i, c);
				}
				break;
			case ImmBranch:
				i=oprom[pos++];
				SATURN_PEEKOP_DIS8(v);
				c=(pc+pos-2+v)&0xfffff;
				sprintf(buffer, mnemonics[level->mnemonic].name[set], i, c);
				break;
			case FieldP:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], P );
				break;
			case FieldWP:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], WP );
				break;
			case FieldXS:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], XS );
				break;
			case FieldX:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], X );
				break;
			case FieldS:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], S );
				break;
			case FieldM:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], M );
				break;
			case FieldB:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], B );
				break;
			case FieldA:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], A );
				break;
			case FieldW:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], W );
				break;
			case AdrA:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], adr_a[oprom[pos++] & 0x7] );
				break;
			case AdrAF:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], adr_af[oprom[pos++] & 0xf] );
				break;
			case AdrB:
				sprintf(buffer, mnemonics[level->mnemonic].name[set], adr_b[oprom[pos++] & 0x7] );
				break;
			}
			break;
		}
		level = opcodes[level->sel];
	}

	return pos;
}
