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

#include "emu.h"
#include "saturnds.h"

#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"

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

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

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

const char saturn_disassembler::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_t)( opcodes.r8(pos) | ( opcodes.r8(pos+1) << 4 ) ); pos+= 2;

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

#define SATURN_PEEKOP_DIS16(v)  v = (int16_t)( opcodes.r8(pos) | ( opcodes.r8(pos+1) << 4 ) | ( opcodes.r8(pos+2) << 8 ) | ( opcodes.r8(pos+3) << 12 ) ); pos += 4;

#define SATURN_PEEKOP_ADR(v)    v = opcodes.r8(pos) | ( opcodes.r8(pos+1) << 4 ) | ( opcodes.r8(pos+2) << 8 ) | ( opcodes.r8(pos+3) << 12 ) | ( opcodes.r8(pos+4) << 16 ); pos += 5;


const char *const saturn_disassembler::mnemonics[][2] = {
	{ "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" }
};



const char *saturn_disassembler::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;
}

const saturn_disassembler::OPCODE saturn_disassembler::opcs[][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,        xconfig },
		{ 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 }
	}
};

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

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

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

saturn_disassembler::saturn_disassembler(config *conf) : m_config(conf)
{
}

u32 saturn_disassembler::opcode_alignment() const
{
	return 1;
}

offs_t saturn_disassembler::disassemble(std::ostream &stream, offs_t pc, const data_buffer &opcodes, const data_buffer &params)
{
	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=opcs[0]; //pointer to current digit
	int op; // currently fetched nibble
	offs_t pos = pc;

	int i,c,v;

	int mnemonics_bank = m_config->get_nonstandard_mnemonics_mode() ? 1 : 0;

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

	return pos - pc;
}
