
/*
 * Copyright (c) 1988 by Sozobon, Limited.  Author: Joseph M Treat
 *
 * Permission is granted to anyone to use this software for any purpose
 * on any computer system, and to redistribute it freely, with the
 * following restrictions:
 * 1) No charge may be made other than reasonable charges for reproduction.
 * 2) Modified versions must be clearly marked as such.
 * 3) The authors are not responsible for any harmful consequences
 *    of using this software, even if they result from defects in it.
 */

#include "jas.h"

INST itable[] = {
{"b$c$s",	O_LAB,	O_NONE,	S_BW,	"x6$c%0d",	F_PC|F_TXT },
{"",		0,	0,	0,	"",		0 },
{"s$C$s",	O_DST,	O_NONE,	S_B,	"x5$c11%0e",	F_B },
#	include "opcodes.h"
};

int ninsts = (sizeof itable) / (sizeof itable[0]);

INST *
ifind( token, misc )
	register char *token;
	short *misc;
{
	register int lo = 4;
	register int hi = ninsts-2;
	register int i, d;
	register INST *ip;

	while ( lo <= hi ) {
		i = (lo + hi) / 2;
		ip = &itable[i];
		d = icmpare( token, ip->mnemon, misc );
		if ( d == 0 ) {
			INST *jp;

			/*
			 * find the first item with this mnemonic
			 */
			for ( jp = ip-1; ; ip = jp-- ) {
				if ( *(ip->mnemon) != *(jp->mnemon) ) {
					break;
				}
				if ( strcmp( ip->mnemon, jp->mnemon) ) {
					break;
				}
			}
			return ip;
		} else if ( d < 0 ) {
			hi = i-1;
		} else {	/* d > 0 */
			lo = i+1;
		}
	}

	/*
	 * here is some special stuff for conditional branches and sets
	 * which were impractical to put in the standard table
	 */
	if ( *token == 'b' ) {
		ip = &itable[0];
		if (! icmpare( token, ip->mnemon, misc ) )
			return ip;
	} else if ( *token == 's' ) {
		ip = &itable[2];
		if (! icmpare( token, ip->mnemon, misc ) )
			return ip;
	}
	return (INST *) NULL;
}

int
icmpare( token, mnemon, misc )
	char *token;
	char *mnemon;
	short *misc;
{
	register int i;
	register char *tp, *mp;

	*misc = 0;
	for ( tp = token, mp = mnemon; *mp; mp++ ) {
		if ( *mp == '$' ) {
			switch ( *++mp ) {
			case 'c':
				i = chk_cond( tp, 0, misc );
				if ( i == 0 )
					return *tp ? *tp : -1;
				tp += i-1;
				break;
			case 'C':
				i = chk_cond( tp, 1, misc );
				if ( i == 0 )
					return *tp ? *tp : -1;
				tp += i-1;
				break;
			case 'd':
				if ( *tp == 'r' )
					*misc |= 0x00;
				else if ( *tp == 'l' )
					*misc |= 0x08;
				else
					return *tp ? *tp : -1;
				break;
			case 's':
				if ( *tp ) {
					if ( *tp != '.' )
						return *tp;
					switch ( *++tp ) {
					case 'b':
						*misc |= 0x01;
						break;
					case 'w':
						*misc |= 0x02;
						break;
					case 'l':
						*misc |= 0x04;
						break;
					default:
						return '.';
					}
				}
				break;
			}
		} else if ( *mp != *tp ) {
			return *tp - *mp;
		}
		if ( *tp )
			tp++;
	}

	return *tp;
}

struct hcc_bug {
	char cc[3];
	char en;
} cctab[] = {
	{ "ra", 0x1 },	/* dbcc start here */
	{ "f",  0x1 },
	{ "t",  0x0 },
	{ "eq", 0x7 },	/* bcc start here */
	{ "ne", 0x6 },
	{ "ge", 0xC },
	{ "gt", 0xE },
	{ "le", 0xF },
	{ "lt", 0xD },
	{ "cc", 0x4 },
	{ "hi", 0x2 },
	{ "ls", 0x3 },
	{ "cs", 0x5 },
	{ "hs", 0x4 },
	{ "lo", 0x5 },
	{ "mi", 0xB },
	{ "pl", 0xA },
	{ "vc", 0x8 },
	{ "vs", 0x9 },
	{ "", 0 }
};

chk_cond( tp, all, misc )
	register char *tp;
	int all;
	short *misc;
{
	register int i;

	i = all ? 0 : 3;
	for ( ; cctab[i].cc[0]; i++ ) {
		if (! strncmp( tp, cctab[i].cc, strlen(cctab[i].cc) ) ) {
			*misc |= ( cctab[i].en << 4 ); 
			return strlen( cctab[i].cc );
		}
	}
	return 0;
}
