/*
 *      MC68HC11 specific processing
 */

#define PAGE1   0x00
#define PAGE2   0x18
#define PAGE3   0x1A
#define PAGE4   0xCD

/* addressing modes */
#define IMMED   0
#define INDX    1
#define INDY    2
#define LIMMED  3       /* long immediate */
#define OTHER   4

int     yflag = 0;      /* YNOIMM, YLIMM, and CPD flag */

/*
 *      localinit --- machine specific initialization
 */
localinit()
{
}

/*
 *      do_op --- process mnemonic
 *
 *	Called with the base opcode and it's class. Optr points to
 *	the beginning of the operand field.
 */
do_op(opcode,class)
int opcode;	/* base opcode */
int class;	/* mnemonic class */
{
	char *skip_white();
	int     dist;   /* relative branch distance */
	int     amode;  /* indicated addressing mode */
	char	*peek;

	/* guess at addressing mode */
	peek = Optr;
	amode = OTHER;
	while( !delim(*peek) && *peek != EOS)  /* check for comma in operand field */
		if( *peek++ == ',' ){
			if( mapdn(*peek) == 'y' )
				amode = INDY;
			else
				amode = INDX;
			break;
			}
	if( *Optr == '#' ) amode = IMMED;

	yflag = 0;
	switch(class){
		case P2INH:
			emit(PAGE2);
		case INH:                       /* inherent addressing */
			emit(opcode);
			return;
		case REL:                       /* relative branches */
			eval();
			dist = Result - (Pc+2);
			emit(opcode);
			if( (dist >127 || dist <-128) && Pass==2){
				error("Branch out of Range");
				emit(lobyte(-2));
				return;
				}
			emit(lobyte(dist));
			return;
		case LONGIMM:
			if( amode == IMMED )
				amode = LIMMED;
		case NOIMM:
			if( amode == IMMED ){
				error("Immediate Addressing Illegal");
				return;
				}
		case GEN:                       /* general addressing */
			do_gen(opcode,amode,PAGE1,PAGE1,PAGE2);
			return;
		case GRP2:
			if( amode == INDY ){
				Cycles++;
				emit(PAGE2);
				amode = INDX;
				}
			if( amode == INDX )
				do_indexed(opcode);
			else{   /* extended addressing */
				eval();
				emit(opcode+0x10);
				eword(Result);
				}
			return;
		case CPD:               /* cmpd */
			if( amode == IMMED )
				amode = LIMMED;
			if( amode == INDY )
				yflag=1;
			do_gen(opcode,amode,PAGE3,PAGE3,PAGE4);
			return;
		case XNOIMM:            /* stx */
			if( amode == IMMED ){
				error("Immediate Addressing Illegal");
				return;
				}
		case XLIMM:             /* cpx, ldx */
			if( amode == IMMED )
				amode = LIMMED;
			do_gen(opcode,amode,PAGE1,PAGE1,PAGE4);
			return;
		case YNOIMM:            /* sty */
			if( amode == IMMED ){
				error("Immediate Addressing Illegal");
				return;
				}
		case YLIMM:             /* cpy, ldy */
			if(amode == INDY)
				yflag=1;
			if( amode == IMMED )
				amode = LIMMED;
			do_gen(opcode,amode,PAGE2,PAGE3,PAGE2);
			return;
		case BTB:               /* bset, bclr */
		case SETCLR:            /* brset, brclr */
			opcode = bitop(opcode,amode,class);

			if (amode == INDX)
				Cycles++;
			if( amode == INDY ){
				Cycles+=2;
				emit(PAGE2);
				amode = INDX;
				}
			emit(opcode);
			eval();
			emit(lobyte(Result));   /* address */
			if( amode == INDX )
				Optr += 2;      /* skip ,x or ,y */
			Optr = skip_white(Optr);
			eval();
			emit(lobyte(Result));   /* mask */
			if( class == SETCLR )
				return;
			Optr = skip_white(Optr);
			eval();
			dist = Result - (Pc+1);
			if( (dist >127 || dist <-128) && Pass==2){
				error("Branch out of Range");
				dist = Old_pc - (Pc+1);
				}
			emit(lobyte(dist));
			return;
		default:
			fatal("Error in Mnemonic table");
		}
}

/*
 *      bitop --- adjust opcode on bit manipulation instructions
 */
bitop(op,mode,class)
int op;
int mode;
int class;
{
	if( mode == INDX || mode == INDY )
		return(op);
	if( class == SETCLR )
		return(op-8);
	else if(class==BTB)
		return(op-12);
	else
		fatal("bitop");
}

/*
 *      do_gen --- process general addressing modes
 */
do_gen(op,mode,pnorm,px,py)
int     op;     /* base opcode */
int     mode;   /* addressing mode */
int     pnorm;  /* page for normal addressing modes: IMM,DIR,EXT */
int     px;     /* page for INDX addressing */
int     py;     /* page for INDY addressing */
{
	switch(mode){
	case LIMMED:
		Optr++;
		epage(pnorm);
		emit(op);
		eval();
		eword(Result);
		break;
	case IMMED:
		Optr++;
		epage(pnorm);
		emit(op);
		eval();
		emit(lobyte(Result));
		break;
	case INDY:
		if(yflag)
			Cycles += 2;
		else
			Cycles += 3;
		epage(py);
		do_indexed(op+0x20);
		break;
	case INDX:
		Cycles+=2;
		epage(px);
		do_indexed(op+0x20);
		break;
	case OTHER:
		eval();
		epage(pnorm);
		if(Force_word){
			emit(op+0x30);
			eword(Result);
			Cycles+=2;
			break;
			}
		if(Force_byte){
			emit(op+0x10);
			emit(lobyte(Result));
			Cycles++;
			break;
			}
		if(Result>=0 && Result <=0xFF){
			emit(op+0x10);
			emit(lobyte(Result));
			Cycles++;
			break;
			}
		else {
			emit(op+0x30);
			eword(Result);
			Cycles+=2;
			break;
			}
		break;
	default:
		error("Unknown Addressing Mode");
	}
}

/*
 *      do_indexed --- handle all wierd stuff for indexed addressing
 */
do_indexed(op)
int op;
{
	char c;

	emit(op);
	eval();
	if( *Optr++ != ',' )
		error("Syntax");
	c = mapdn(*Optr++);
	if( c != 'x' && c != 'y')
		warn("Indexed Addressing Assumed");
	if( Result < 0 || Result > 255)
		warn("Value Truncated");
	emit(lobyte(Result));
}

/*
 *      epage --- emit page prebyte
 */
epage(p)
int p;
{
	if( p != PAGE1 )        /* PAGE1 means no prebyte */
		emit(p);
}
