# sleigh specification file for Motorola 6805
define endian=big;
define alignment=1;

define space RAM     type=ram_space      size=2  default;
define space register type=register_space size=1;

define register offset=0x00  size=1 [ A X ];
define register offset=0x20 size=2  [ PC SP];
define register offset=0x30 size=1 [H I N Z C];	# status bits

define RAM offset=0x3ffc size=2 [ SWI_VECTOR ];
#TOKENS

define token opbyte (8)
   op       = (0,7)
   op4_7	= (4,7)
   op4_6	= (4,6)
   n		= (1,3)
   bit_0	= (0,0)
;

define token data8 (8)
   imm8		= (0,7)
   rel		= (0,7) signed
;

define token data (16)
	imm16 = (0,15)
;
################################################################
# Pseudo Instructions
################################################################

define pcodeop readIRQ;

################################################################
REL: reloc		is rel	[ reloc = inst_next + rel; ] { export *:2 reloc; } 

OP1: "#"imm8	is op4_6=2; imm8		{ tmp:1 = imm8; export tmp; }
OP1: imm8 		is op4_6=3; imm8		{ export *:1 imm8; }
OP1: imm16 		is op4_6=4; imm16     	{ export *:1 imm16; }
OP1: imm16,X  	is op4_6=5 & X; imm16 	{ tmp:2 = imm16 + zext(X); export *:1 tmp; }
OP1: imm8,X   	is op4_6=6 & X; imm8  	{ tmp:2 = imm8 + zext(X); export *:1 tmp; }
OP1: X			is op4_6=7 & X			{ tmp:2 = zext(X); export *:1 tmp; }

ADDR: imm8 			is op4_6=3; imm8		{ export *:1 imm8; }
ADDR: imm16 		is op4_6=4; imm16   	{ export *:1 imm16; }
ADDRI: imm16,X  	is op4_6=5 & X; imm16 	{ tmp:2 = imm16 + zext(X); export tmp; }
ADDRI: imm8,X   	is op4_6=6 & X; imm8  	{ tmp:2 = imm8 + zext(X); export tmp; }
ADDRI: X			is op4_6=7 & X			{ tmp:2 = zext(X); export tmp; }


DIRECT: imm8	is imm8					{ export *:1 imm8; }

:ADC OP1     is (op=0xA9 | op=0xB9 | op=0xC9 | op=0xD9 | op=0xE9 | op=0xF9) ... & OP1
{
	 local op1 = OP1;

	# compute half carry
	local halfop1 = op1 & 0xF;	
	local halfA = A & 0xF;
	local halfresult = halfop1 + halfA + C;
	H = (halfresult >> 4) & 1;

	local result = A + op1;
	local tmpC = carry(A, op1);

	A = result + C;
	C = carry(result, C);
	C = C | tmpC;
	Z = (A == 0);
	N = (A s< 0);
}
:ADD OP1     is (op=0xAB | op=0xBB | op=0xCB | op=0xDB | op=0xEB | op=0xFB) ... & OP1
{ 
	local op1 = OP1;

	# compute half carry
	local halfop1 = op1 & 0xF;	
	local halfA = A & 0xF;
	local halfresult = halfop1 + halfA;
	H = (halfresult >> 4) & 1;

	C = carry(A, op1);
	A = A + op1; 
	Z = (A == 0);
	N = (A s< 0);
}

:AND OP1     is (op=0xA4 | op=0xB4 | op=0xC4 | op=0xD4 | op=0xE4 | op=0xF4) ... & OP1
{ 
	A = A & OP1; 
	Z = (A == 0);
	N = (A s< 0);
}

:ASLA		is op=0x48 
{
	C = A >> 7;
	A = A << 1;
	Z = (A == 0);
	N = (A s< 0);	
}
:ASLX		is op=0x58 
{
	C = X >> 7;
	X = X << 1;
	Z = (X == 0);
	N = (X s< 0);	
}
:ASL OP1	is (op=0x38 | op=0x68 | op=0x78) ... & OP1 
{
	local tmp = OP1;
	C = tmp >> 7;
	tmp = tmp << 1;
	OP1 = tmp;
	Z = (tmp == 0);
	N = (tmp s< 0);	
}
:ASRA		is op=0x47 
{
	C = A & 1;
	A = A s>> 1;
	Z = (A == 0);
	N = (A s< 0);	
}
:ASRX		is op=0x57 
{
	C = X & 1;
	X = X s>> 1;
	Z = (X == 0);
	N = (X s< 0);	
}
:ASR OP1	is (op=0x37 | op=0x67 | op=0x77) ... & OP1 
{
	local tmp = OP1;
	C = tmp & 1;
	tmp = tmp s>> 1;
	OP1 = tmp;
	Z = (tmp == 0);
	N = (tmp s< 0);	
}

:BCC REL	is op=0x24;REL
{
	if (C == 0) goto REL;
}

:BCLR n,DIRECT	is op4_7=1 & bit_0=1 & n; DIRECT {
	local mask = ~(1 << n);
	DIRECT = DIRECT & mask;
}
:BCS REL	is op=0x25;REL
{
	if (C) goto REL;
}
:BEQ REL	is op=0x27;REL
{
	if (Z) goto REL;
}
:BHCC REL	is op=0x28;REL
{
	if (H == 0) goto REL;
}
:BHCS REL	is op=0x29;REL
{
	if (H) goto REL;
}
:BHI REL	is op=0x22;REL
{
	local tmp = C + Z;
	if (tmp == 0) goto REL;
}

#:BHS REL	is op=0x24;REL		See BCC

:BIH REL	is op=0x2F;REL
{
	tmp:1 = readIRQ();
	if (tmp) goto REL;
}
:BIL REL	is op=0x2E;REL
{
	tmp:1 = readIRQ();
	if (tmp == 0) goto REL;
}
:BIT OP1     is (op=0xA5 | op=0xB5 | op=0xC5 | op=0xD5 | op=0xE5 | op=0xF5) ... & OP1
{
	local result = A & OP1;
	Z = (result == 0);
	N = (result s< 0);
}
#:BLO REL	is op=0x25;REL		see BCS

:BLS REL	is op=0x23;REL
{
	local tmp = C + Z;
	if (tmp) goto REL;
}

:BMC REL	is op=0x2C;REL
{
	if (I == 0) goto REL;
}
:BMI REL	is op=0x2B;REL
{
	if (N) goto REL;
}
:BMS REL	is op=0x2D;REL
{
	if (I) goto REL;
}
:BNE REL	is op=0x26;REL
{
	if (Z == 0) goto REL;
}
:BPL REL	is op=0x2A;REL
{
	if (N == 0) goto REL;
}
:BRA REL	is op=0x20;REL
{
	goto REL;
}

:BRN REL	is op=0x21;REL
{
}

:BRCLR n,DIRECT,REL		is op4_7=0 & bit_0=1 & n; DIRECT; REL
{
	local mask = (1 << n);
	local result = DIRECT & mask;
	if (result == 0) goto REL;
}

:BRSET n,DIRECT,REL		is op4_7=0 & bit_0=0 & n; DIRECT; REL
{
	local mask = (1 << n);
	local result = DIRECT & mask;
	if (result != 0) goto REL;
}

:BSET n,DIRECT	is op4_7=1 & bit_0=0 & n; DIRECT {
	local mask = (1 << n);
	DIRECT = DIRECT | mask;
}

:BSR REL		is op=0xAD; REL 
{
	SP=SP-1;
	*:2 SP = inst_next;
	SP=SP-1; 
	call REL;
}

:CLC		is op=0x98
{
	C = 0;
}

:CLI		is op=0x9A
{
	I = 0;
}
:CLRA		is op=0x4F 
{
	A = 0;
	Z = 1;
	N = 0;
}
:CLRX		is op=0x5F 
{
	X = 0;
	Z = 1;
	N = 0;
}
:CLR OP1	is (op=0x3F | op=0x6F | op=0x7F) ... & OP1 
{
	OP1 = 0;
	Z = 1;
	N = 0;
}
:CMP OP1     is (op=0xA1 | op=0xB1 | op=0xC1 | op=0xD1 | op=0xE1 | op=0xF1) ... & OP1
{ 
	local op1 = OP1;
	local tmp = A - op1;
	Z = tmp == 0;
	N = tmp s< 0;
	C = (A < op1);
}

:COMA		is op=0x43 
{
	A = ~A;
	Z = (A == 0);
	N = (A s< 0);
	C = 1;
}
:COMX		is op=0x53 
{
	X = ~X;
	Z = (X == 0);
	N = (X s< 0);
	C = 1;
}
:COM OP1	is (op=0x33 | op=0x63 | op=0x73) ... & OP1 
{
	local tmp = ~OP1;
	OP1 = tmp;
	Z = (tmp == 0);
	N = (tmp s< 0);
	C = 1;
}
:CPX OP1     is (op=0xA3 | op=0xB3 | op=0xC3 | op=0xD3 | op=0xE3 | op=0xF3) ... & OP1
{ 
	local op1 = OP1;
	local tmp = X - op1;
	Z = tmp == 0;
	N = tmp s< 0;
	C = (X < op1);
}
:DECA		is op=0x4A 
{
	A = A - 1;
	Z = (A == 0);
	N = (A s< 0);
}
:DECX		is op=0x5A 
{
	X = X - 1;
	Z = (X == 0);
	N = (X s< 0);
}
:DEC OP1	is (op=0x3A | op=0x6A | op=0x7A) ... & OP1 
{
	local tmp = OP1 - 1;
	OP1 = tmp;
	Z = (tmp == 0);
	N = (tmp s< 0);
}
:EOR OP1     is (op=0xA8 | op=0xB8 | op=0xC8 | op=0xD8 | op=0xE8 | op=0xF8) ... & OP1
{ 
	local op1 = OP1;
	A = A ^ op1;
	Z = A == 0;
	N = A s< 0;
}
:INCA		is op=0x4C 
{
	A = A + 1;
	Z = (A == 0);
	N = (A s< 0);
}
:INCX		is op=0x5C 
{
	X = X + 1;
	Z = (X == 0);
	N = (X s< 0);
}
:INC OP1	is (op=0x3C | op=0x6C | op=0x7C) ... & OP1 
{
	local tmp = OP1 + 1;
	OP1 = tmp;
	Z = (tmp == 0);
	N = (tmp s< 0);
}
:JMP ADDR	is (op=0xBC | op=0xCC) ... & ADDR
{
	goto ADDR;
}

:JMP ADDRI	is (op=0xDC | op=0xEC | op=0xFC) ... & ADDRI
{
	goto [ADDRI];
}


:JSR ADDR	is (op=0xBD | op=0xCD) ... & ADDR
{
	*:2 (SP-1) = inst_next;
	SP=SP-2; 
	call ADDR;
}
:JSR ADDRI	is (op=0xDD | op=0xED | op=0xFD) ... & ADDRI
{
	*:2 (SP-1) = inst_next;
	SP=SP-2; 
	call [ADDRI];
}

:LDA OP1     is (op=0xA6 | op=0xB6 | op=0xC6 | op=0xD6 | op=0xE6 | op=0xF6) ... & OP1
{ 
	A = OP1;
	Z = A == 0;
	N = A s< 0;
}

:LDX OP1     is (op=0xAE | op=0xBE | op=0xCE | op=0xDE | op=0xEE | op=0xFE) ... & OP1
{ 
	X = OP1;
	Z = X == 0;
	N = X s< 0;
}

## Logical Shift left is same as arithmetic shift left
#:LSLA		is op=0x48 
#:LSLX		is op=0x58 
#:LSL OP1	is (op=0x38 | op=0x68 | op=0x78) ... & OP1 
:LSRA		is op=0x44 
{
	C = A & 1;
	A = A >> 1;
	Z = (A == 0);
	N = 0;	
}
:LSRX		is op=0x54 
{
	C = X & 1;
	X = X >> 1;
	Z = (X == 0);
	N = 0;	
}
:LSR OP1	is (op=0x34 | op=0x64 | op=0x74) ... & OP1 
{
	local tmp = OP1;
	C = tmp & 1;
	tmp = tmp >> 1;
	OP1 = tmp;
	Z = (tmp == 0);
	N = 0;	
}

:MUL		is op=0x42
{
	op1:2 = zext(A);
	op2:2 = zext(X);
	local result = op1 * op2;
	A = result:1;
	result = result >> 8;
	X = result:1;
}

:NEGA		is op=0x40 
{
	C = A != 0;
	A = -A;
	Z = (A == 0);
	N = (A s< 0);
}
:NEGX		is op=0x50 
{
	C = X != 0;
	X = -X;
	Z = (X == 0);
	N = (X s< 0);
}
:NEG OP1	is (op=0x30 | op=0x60 | op=0x70) ... & OP1 
{
	local op1 = OP1;
	C = op1 != 0;
	OP1 = -op1;
	Z = (op1 == 0);
	N = (op1 s< 0);
}

:NOP		is op = 0x9D
{
}

:ORA OP1     is (op=0xAA | op=0xBA | op=0xCA | op=0xDA | op=0xEA | op=0xFA) ... & OP1
{ 
	A = A | OP1; 
	Z = (A == 0);
	N = (A s< 0);
}

:ROLA		is op=0x49 
{
	local tmp = C ;
	C = A >> 7;
	A = A << 1;
	A = A | tmp;
	Z = (A == 0);
	N = (A s< 0);	
}
:ROLX		is op=0x59 
{
	local tmp = C;
	C = X >> 7;
	X = X << 1;
	X = X | tmp;
	Z = (X == 0);
	N = (X s< 0);	
}
:ROL OP1	is (op=0x39 | op=0x69 | op=0x79) ... & OP1 
{
	local tmpC = C;
	local op1 = OP1;
	C = op1 >> 7;
	local result = op1 << 1;
	result = result | tmpC;
	OP1 = result;
	Z = (result == 0);
	N = (result s< 0);	
}
:RORA		is op=0x46 
{
	local tmpC = C << 7;
	C = A & 1;
	A = A s>> 1;
	A = A | tmpC;
	Z = (A == 0);
	N = (A s< 0);	
}
:RORX		is op=0x56 
{
	local tmpC = C << 7;
	C = X & 1;
	X = X s>> 1;
	X = X | tmpC;
	Z = (X == 0);
	N = (X s< 0);	
}
:ROR OP1	is (op=0x36 | op=0x66 | op=0x76) ... & OP1 
{
	local tmpC = C << 7;
	local tmp = OP1;
	C = tmp & 1;
	tmp = tmp s>> 1;
	tmp = tmp | tmpC;
	OP1 = tmp;
	Z = (tmp == 0);
	N = (tmp s< 0);	
}

:RSP		is op = 0x9C
{
	SP = 0xff;
}

:RTI		is op = 0x80
{
	SP = SP+1;
	local ccr = *:1 SP;
	H = ccr[4,1];
	I = ccr[3,1];
	N = ccr[2,1];
	Z = ccr[1,1];
	C = ccr[0,1];
	
	SP = SP+1;
	A = *:1 SP;
	
	SP = SP+1;
	X = *:1 SP;
	SP = SP+1;
	tmp:2 = *:2 SP;
	SP = SP+1;
	
	return [tmp];
}

:RTS		is op = 0x81
{
	SP = SP+1;
	tmp:2 = *:2 SP;
	SP = SP+1;
	
	return [tmp];
}

:SBC OP1     is (op=0xA2 | op=0xB2 | op=0xC2 | op=0xD2 | op=0xE2 | op=0xF2) ... & OP1
{ 
	local op1 = OP1;
	local tmp = A - op1 - C;
	Z = tmp == 0;
	N = tmp s< 0;
	C = ((A <= op1) * C) | (A < op1);
	A = tmp;
}

:SEC 		is op = 0x99 
{
	C = 1;
}

:SEI 		is op = 0x9B 
{
	I = 1;
}

:STA OP1	is (op=0xB7 | op=0xC7 | op=0xD7 | op=0xE7 | op=0xF7) ... & OP1
{
	OP1 = A;
	Z = A == 0;
	N = A s< 0;
}

:STOP		is op=0x8E
{
	I = 0;
}

:STX OP1	is (op=0xBF | op=0xCF | op=0xDF | op=0xEF | op=0xFF) ... & OP1
{
	OP1 = X;
	Z = X == 0;
	N = X s< 0;
}

:SUB OP1     is (op=0xA0 | op=0xB0 | op=0xC0 | op=0xD0 | op=0xE0 | op=0xF0) ... & OP1
{ 
	local op1 = OP1;
	C = (A < op1);
	A = A - op1;
	Z = A == 0;
	N = A s< 0;
	A = A;
}

:SWI		is op=0x83
{
	SP=SP-1;
	*:2 SP = inst_next;
	SP=SP-1; 
	*:1 SP = X;
	SP=SP-1;
	*:1 SP = A;
	tmp:1 = 0b11100000 | (H << 4) | (I << 3) | (N << 2) | ( Z << 1) | C;
	SP=SP-1;
	*:1 SP = tmp;
	I = 1;
	call [SWI_VECTOR];
}

:TAX	is op=0x97 
{
	X = A;
}
 
:TSTA		is op=0x4D 
{
	Z = (A == 0);
	N = (A s< 0);	
}
:TSTX		is op=0x5D 
{
	Z = (X == 0);
	N = (X s< 0);	
}
:TST OP1	is (op=0x3D | op=0x6D | op=0x7D) ... & OP1 
{
	local op1 = OP1;
	Z = (op1 == 0);
	N = (op1 s< 0);	
}
 
:TXA	is op=0x9F 
{
	A = X;
}

:WAIT	is op=0x8f 
{
	I = 0;
}
 
