/*
 *      do1.c	-	MC6801 specific processing
 *
 *	From Motorola BBS.
 *	See ../doc/ChangeLog to examine and/or add change descriptions.
 */

/* addressing modes */
#define IMMED   0       /* immediate */
#define IND     1       /* indexed */
#define OTHER   2       /* NOTA */

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

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


	if ( class == INH ) { /* inherent addressing */
			emit(opcode);
			return;
		}
	/* guess at addressing mode */
	peek = Optr;
	amode = OTHER;
	if( head(Operand,"X") || head(Operand,"x") ) {
		if( delim(*(Operand+1)) )
			amode = IND;
		}
	else while( !delim(*peek) ) { /* check for comma in operand field */
		if( *peek == ',' ){
				if ( (peek != Optr) && ((*(peek-1) == '\\') || (*(peek-1) == '\'' )) ) {
					peek++; /* skip quoted comma or literal comma */
					continue;
				} else {
					peek++;
					amode = IND;
					break;
				}
			}
			else
				peek++;
		}
	if( *Optr == '#' ) amode = IMMED;

	switch(class){
		case GEN:                       /* general addressing */
			do_gen(opcode,amode);
			return;
		case REL:                       /* relative branches */
			if( eval() )
				dist = Result - (Pc+2);
			else dist = -2;
			emit(opcode);
			if( (dist >127 || dist <-128) && Pass==2){
				error("Branch out of Range");
				dist = -2;
				}
			emit(lobyte(dist));
			return;
		case NOIMM:
			if( amode == IMMED){
				error("Immediate Addressing Illegal");
				return;
				}
			do_gen(opcode,amode);
			return;
		case LONGIMM:
			if( amode == IMMED ){
				emit(opcode);
				Optr++;
				eval();
				eword(Result);
				return;
				}
			do_gen(opcode,amode);
			return;
		case GRP2:
			if( amode == IND ){
				do_indexed(opcode);
				return;
				}
			/* extended addressing */
			eval();
			emit(opcode+0x10);
			eword(Result);
			return;
		default:
			fatal("Error in Mnemonic table");
		}
}

/*
 *      do_gen --- process general addressing modes
 */
void
do_gen(int op, int mode)
{
	if( mode == IMMED){
		Optr++;
		emit(op);
		eval();
		emit(lobyte(Result));
		return;
		}
	else if( mode == IND ){
		Cycles+=2;
		do_indexed(op+0x20);
		return;
		}
	else if( mode == OTHER){
		eval();
		if(Force_word){
			emit(op+0x30);
			eword(Result);
			Cycles+=2;
			return;
			}
		if(Force_byte){
			emit(op+0x10);
			emit(lobyte(Result));
			Cycles++;
			return;
			}
		if(Result>=0 && Result <=0xFF){
			emit(op+0x10);
			emit(lobyte(Result));
			Cycles++;
			return;
			}
		else {
			emit(op+0x30);
			eword(Result);
			Cycles+=2;
			return;
			}
		}
	else {
		error("Unknown Addressing Mode");
		return;
		}
}

/*
 *      do_indexed --- handle all weird stuff for indexed addressing
 */
void
do_indexed(int op)
{
	emit(op);
	if( *Optr != ',' && !head(Operand,"X") && !head(Operand,"x") ) {
		eval();
	        if( !( *Optr++ == ',' && ( mapdn(*Optr) == 'x') ) )
			warn("Indexed Addressing Assumed");
		}
        else {			/* if no expression, fake it */
                Force_word = NO;
                Force_byte = NO;
                Result = 0;
		if( *Optr == ',' ) Optr++;
		if( mapdn(*Optr) != 'x' )
			warn("Indexed Addressing Assumed");
                }
	if( Result < 0 || Result > 255)
		warn("Value Truncated");
	emit(lobyte(Result));
}
