/*------------------------------------------------------------------*/
/*								    */
/*		      MC68000 Cross Assembler			    */
/*								    */
/*	      Copyright	(c) 1985 by Brian R. Anderson		    */
/*								    */
/*	   Opcode table	and scan routine - January 6, 1989	    */
/*								    */
/*   This program may be copied	for personal, non-commercial use    */
/*   only, provided that the above copyright notice is included	    */
/*   on	all copies of the source code.	Copying	for any	other use   */
/*   without the consent of the	author is prohibited.		    */
/*								    */
/*------------------------------------------------------------------*/
/*								    */
/*		Originally published (in Modula-2) in		    */
/*	    Dr.	Dobb's Journal, April, May, and June 1986.          */
/*								    */
/*	 AmigaDOS conversion copyright 1989 by Charlie Gibbs.	    */
/*								    */
/*------------------------------------------------------------------*/

#include <stdio.h>
#include "a68kdef.h"
#include "a68kglb.h"

/* Functions */
extern int  LineParts(), ObjDir();
extern int  GetInstModeSize(), GetMultReg(), CountNest();
extern int  ReadSymTab(), GetArgs(), GetAReg(),	OpenIncl();
extern long AddrBndW(),	AddrBndL(), GetValue(),	CalcValue();
extern char *AddName(),	*GetField();
extern struct SymTab *NextSym();
extern struct SymTab **HashIt();



int Instructions (loc) int loc;
/* Looks up opcode and addressing mode bit patterns
   If the opcode corresponds to	an executable instruction,
     returns TRUE with the following fields set	up:
	Op	 - operation code bits
	AdrModeA - addressing mode bits
	AdrModeB - more	addressing mode	bits
	Dir	 - None
   If the opcode corresponds to	a directive (AdrModeA in the table
     is	0xFFFF), returns TRUE with the following fields	set up:
	Op	 - 0
	AdrModeA - 0
	AdrModeB - 0
	Dir	 - the appropriate directive value
   If not found, returns FALSE with all	the above fields set to	zero.

   NOTE: The binary search doesn't use strcmp because this function
    returns incorrect values under MS-DOS Lattice 2.12.		      */
{
    static int maxinst = 0;		/* Size	of opcode table	*/
    static int limits['Z'-'A'+2];       /* Table limits by first letter */
    register char *i, *j;
    register int  lower, upper,	mid;	/* Binary search controls */

/* Opcode table	*/

    struct OpTab {
	char Mnem[8];	/* Instruction mnemonic	*/
	int  OpBits;	/* Op code bits	*/
	int  AMA;	/* Address mode	bits */
	int  AMB;	/* More	address	mode bits */
    };

    static struct OpTab	MnemTab[] = {
	"=",     0,      0xFFFF, Equ,
	"ABCD",  0xC100, Rx911 | RegMem3 | Ry02, 0,
	"ADD",   0xD000, OpM68D, EA05y,
	"ADDA",  0xD000, OpM68A, EA05a,
	"ADDI",  0x0600, 0, Size67 | EA05e | Exten,
	"ADDQ",  0x5000, Data911, Size67 | EA05d,
	"ADDX",  0xD100, Rx911 | RegMem3 | Ry02, Size67,
	"AND",   0xC000, OpM68D, EA05x,
	"ANDI",  0x0200, 0, Size67 | EA05e | Exten,
	"ASL",   0xE100, CntR911, 0,
	"ASR",   0xE000, CntR911, 0,
	"BCC",   0x6400, Brnch, 0,
	"BCHG",  0x0040, 0, EA05e | Exten | Bit811,
	"BCLR",  0x0080, 0, EA05e | Exten | Bit811,
	"BCS",   0x6500, Brnch, 0,
	"BEQ",   0x6700, Brnch, 0,
	"BGE",   0x6C00, Brnch, 0,
	"BGT",   0x6E00, Brnch, 0,
	"BHI",   0x6200, Brnch, 0,
	"BLE",   0x6F00, Brnch, 0,
	"BLS",   0x6300, Brnch, 0,
	"BLT",   0x6D00, Brnch, 0,
	"BMI",   0x6B00, Brnch, 0,
	"BNE",   0x6600, Brnch, 0,
	"BPL",   0x6A00, Brnch, 0,
	"BRA",   0x6000, Brnch, 0,
	"BSET",  0x00C0, 0, EA05e | Exten | Bit811,
	"BSR",   0x6100, Brnch, 0,
	"BSS",   0,      0xFFFF, BSS,
	"BTST",  0x0000, 0, EA05c | Exten | Bit811,
	"BVC",   0x6800, Brnch, 0,
	"BVS",   0x6900, Brnch, 0,
	"CHK",   0x4180, Rx911, EA05b,
	"CLR",   0x4200, 0, Size67 | EA05e,
	"CMP",   0xB000, OpM68C, EA05a,
	"CMPA",  0xB000, OpM68A, EA05a,
	"CMPI",  0x0C00, 0, Size67 | EA05e | Exten,
	"CMPM",  0xB108, Rx911 | Ry02, Size67,
	"CNOP",  0,      0xFFFF, Cnop,
	"CODE",  0,      0xFFFF, CSeg,
	"CSEG",  0,      0xFFFF, CSeg,
	"DATA",  0,      0xFFFF, DSeg,
	"DBCC",  0x54C8, DecBr, 0,
	"DBCS",  0x55C8, DecBr, 0,
	"DBEQ",  0x57C8, DecBr, 0,
	"DBF",   0x51C8, DecBr, 0,
	"DBGE",  0x5CC8, DecBr, 0,
	"DBGT",  0x5EC8, DecBr, 0,
	"DBHI",  0x52C8, DecBr, 0,
	"DBLE",  0x5FC8, DecBr, 0,
	"DBLS",  0x53C8, DecBr, 0,
	"DBLT",  0x5DC8, DecBr, 0,
	"DBMI",  0x5BC8, DecBr, 0,
	"DBNE",  0x56C8, DecBr, 0,
	"DBPL",  0x5AC8, DecBr, 0,
	"DBRA",  0x51C8, DecBr, 0,
	"DBT",   0x50C8, DecBr, 0,
	"DBVC",  0x58C8, DecBr, 0,
	"DBVS",  0x59C8, DecBr, 0,
	"DC",    0,      0xFFFF, DC,
	"DCB",   0,      0xFFFF, DCB,
	"DIVS",  0x81C0, Rx911, EA05b,
	"DIVU",  0x80C0, Rx911, EA05b,
	"DS",    0,      0xFFFF, DS,
	"DSEG",  0,      0xFFFF, DSeg,
	"END",   0,      0xFFFF, End,
	"ENDC",  0,      0xFFFF, EndC,
	"ENDIF", 0,      0xFFFF, EndC,
	"EOR",   0xB000, OpM68X, EA05e,
	"EORI",  0x0A00, 0, Size67 | EA05e | Exten,
	"EQU",   0,      0xFFFF, Equ,
	"EQUR",  0,      0xFFFF, Equr,
	"EVEN",  0,      0xFFFF, Even,
	"EXG",   0xC100, OpM37, 0,
	"EXT",   0x4800, OpM68S, 0,
	"FAR",   0,      0xFFFF, Far,
	"IDNT",  0,      0xFFFF, Idnt,
	"IFC",   0,      0xFFFF, IfC,
	"IFD",   0,      0xFFFF, IfD,
	"IFEQ",  0,      0xFFFF, IfEQ,
	"IFGE",  0,      0xFFFF, IfGE,
	"IFGT",  0,      0xFFFF, IfGT,
	"IFLE",  0,      0xFFFF, IfLE,
	"IFLT",  0,      0xFFFF, IfLT,
	"IFNC",  0,      0xFFFF, IfNC,
	"IFND",  0,      0xFFFF, IfND,
	"IFNE",  0,      0xFFFF, IfNE,
	"ILLEGAL", 0x4AFC, 0, 0,
	"INCLUDE", 0,    0xFFFF, Include,
	"JMP",   0x4EC0, 0, EA05f,
	"JSR",   0x4E80, 0, EA05f,
	"LEA",   0x41C0, Rx911, EA05f,
	"LINK",  0x4E50, Ry02, Exten,
	"LIST",  0,      0xFFFF, DoList,
	"LSL",   0xE308, CntR911, 0,
	"LSR",   0xE208, CntR911, 0,
	"MACRO", 0,      0xFFFF, Macro,
	"MOVE",  0x0000, 0, Sz1213A | EA611,
	"MOVEA", 0x0040, Rx911, Sz1213 | EA05a,
	"MOVEM", 0x4880, 0, Size6 | EA05z | Exten,
	"MOVEP", 0x0008, OpM68R, Exten,
	"MOVEQ", 0x7000, Data07, 0,
	"MULS",  0xC1C0, Rx911, EA05b,
	"MULU",  0xC0C0, Rx911, EA05b,
	"NBCD",  0x4800, 0, EA05e,
	"NEAR",  0,      0xFFFF, Near,
	"NEG",   0x4400, 0, Size67 | EA05e,
	"NEGX",  0x4000, 0, Size67 | EA05e,
	"NOL",   0,      0xFFFF, NoList,
	"NOLIST",0,      0xFFFF, NoList,
	"NOP",   0x4E71, 0, 0,
	"NOT",   0x4600, 0, Size67 | EA05e,
	"OR",    0x8000, OpM68D, EA05x,
	"ORG",   0,      0xFFFF, Org,
	"ORI",   0x0000, 0, Size67 | EA05e | Exten,
	"PAGE",  0,      0xFFFF, Page,
	"PEA",   0x4840, 0, EA05f,
	"PUBLIC",0,      0xFFFF, Public,
	"REG",   0,      0xFFFF, Reg,
	"RESET", 0x4E70, 0, 0,
	"ROL",   0xE718, CntR911, 0,
	"ROR",   0xE618, CntR911, 0,
	"RORG",  0,      0xFFFF, Org,
	"ROXL",  0xE510, CntR911, 0,
	"ROXR",  0xE410, CntR911, 0,
	"RTE",   0x4E73, 0, 0,
	"RTR",   0x4E77, 0, 0,
	"RTS",   0x4E75, 0, 0,
	"SBCD",  0x8100, Rx911 | RegMem3 | Ry02, 0,
	"SCC",   0x54C0, 0, EA05e,
	"SCS",   0x55C0, 0, EA05e,
	"SECTION", 0,    0xFFFF, Section,
	"SEQ",   0x57C0, 0, EA05e,
	"SET",   0,      0xFFFF, Set,
	"SF",    0x51C0, 0, EA05e,
	"SGE",   0x5CC0, 0, EA05e,
	"SGT",   0x5EC0, 0, EA05e,
	"SHI",   0x52C0, 0, EA05e,
	"SLE",   0x5FC0, 0, EA05e,
	"SLS",   0x53C0, 0, EA05e,
	"SLT",   0x5DC0, 0, EA05e,
	"SMI",   0x5BC0, 0, EA05e,
	"SNE",   0x56C0, 0, EA05e,
	"SPC",   0,      0xFFFF, Space,
	"SPL",   0x5AC0, 0, EA05e,
	"ST",    0x50C0, 0, EA05e,
	"STOP",  0x4E72, 0, Exten,
	"SUB",   0x9000, OpM68D, EA05y,
	"SUBA",  0x9000, OpM68A, EA05a,
	"SUBI",  0x0400, 0, Size67 | EA05e | Exten,
	"SUBQ",  0x5100, Data911, Size67 | EA05d,
	"SUBX",  0x9100, Rx911 | RegMem3 | Ry02, Size67,
	"SVC",   0x58C0, 0, EA05e,
	"SVS",   0x59C0, 0, EA05e,
	"SWAP",  0x4840, Ry02, 0,
	"TAS",   0x4AC0, 0, EA05e,
	"TITLE", 0,      0xFFFF, Title,
	"TRAP",  0x4E40, Data03, 0,
	"TRAPV", 0x4E76, 0, 0,
	"TST",   0x4A00, 0, Size67 | EA05e,
	"UNLK",  0x4E58, Ry02, 0,
	"XDEF",  0,      0xFFFF, Xdef,
	"XREF",  0,      0xFFFF, Xref,
	"",0,0,0};          /* End-of-table flag */



    if (maxinst	== 0) {		/* Determine size of opcode table */
	while (MnemTab[maxinst].Mnem[0])
	    maxinst++;
	limits[0] = 0;
	limits['Z'-'A'+1] = maxinst;
	mid = 0;
	for (lower = 0;	lower <	maxinst; lower++) {
	    upper = (unsigned int) MnemTab[lower].Mnem[0] - 'A' + 1;
	    if (upper != mid) {
		if (upper > 0) {	/* Start of the	next letter */
		    mid++;
		    while (mid < upper)
			limits[mid++] =	lower;
		    limits[mid]	= lower;
		}
	    }
	}
	mid++;
	while (mid < 'Z'-'A'+1) {
	    limits[mid++] = maxinst;	/* In case we didn't get to Z */
	}
    }
    mid	= (unsigned int) OpCode[0] - 'A' + 1;
    if (mid < 0) {			/* This	catches	stuff like "=" */
	lower =	0;
	upper =	limits[1];
    } else if (mid > 'Z'-'A'+1) {
	lower =	upper =	0;		/* Reject this one */
    } else {
	lower =	limits[mid++];
	upper =	limits[mid];
    }
    while (lower < upper) {
	mid = (lower + upper) /	2;	/* Search opcode table */
	for (i = OpCode, j = MnemTab[mid].Mnem;	*i == *j; i++, j++)
	    if (*i == '\0')
		break;		/* Find	first non-match	*/
	if (*i < *j)
	    upper = mid;	/* Search lower	half of	table */
	else if	(*i > *j)
	    lower = mid	+ 1;	/* Search upper	half of	table */
	else if	(MnemTab[mid].AMA != 0xFFFF) {	/* Found it */
	    Op = MnemTab[mid].OpBits;	/* Executable instruction */
	    AdrModeA = MnemTab[mid].AMA;
	    AdrModeB = MnemTab[mid].AMB;
	    Dir	= None;
	    return (TRUE);
	} else {
	    Op = AdrModeA = AdrModeB = 0;	/* Directive */
	    Dir	= MnemTab[mid].AMB;
	    return (TRUE);
	}
    }
    Op = AdrModeA = AdrModeB = Dir = 0;
    return (FALSE);			/* Didn't find it */
}
