File:  [Research Unix] / researchv9 / cmd / sun / as / instruction.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:21:59 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv9-SUN3_old, researchv9-SUN3, HEAD
researchv9-SUN3(old)

#ifndef lint
static	char sccsid[] = "@(#)instruction.c 1.1 86/02/03 Copyr 1985 Sun Micro";
#endif

/*
 * Copyright (c) 1985 by Sun Microsystems, Inc.
 */

#include "as.h"
#if C2
#include "c2.h"
#endif

extern char *malloc();
struct oper *newoperand();
struct oper  operands[OPERANDS_MAX];
int numops, code_length;

#if C2
NODE first = { OP_FIRST, SUBOP_OTHER, &first, &first };

/* does this branch read the c or v bit of the condition code? */
char read_cc_cv[]={ 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0 };
static struct ins_bkt * moveq = NULL;
#endif

instruction( ip )
    register struct ins_bkt *ip;
{
#if C2
    register NODE *np;
#endif
    register i;

    if ((ip->xflags_i&I20) && !ext_instruction_set)
	PROG_ERROR( E_OPCODE );
    i = 0;
    if (ip->noper_i != numops && ip->noper_i <= OPERANDS_MAX){
	if ( (ip->touchop_i&TOUCH1(TOUCHMASK)) == TOUCH1(SPEC(2)) && numops==1 && ip->subop_i == SUBOP_W )
	    /* shifts are a special case...*/
	    i = 0;
	else if ( (ip->touchop_i&TOUCH1(TOUCHMASK)) == TOUCH1(SPEC(6)) && numops==0 )
	    /* so is rts */
	    i = 0;
	else
	    i = (E_NUMOPS);
    } else switch (ip->noper_i){
    default: i = 0; break;
    case 1:
	    i = operand_ok( ip, &operands[0], (struct oper *)NULL, (struct oper *)NULL); break;
    case 2:
	    i = operand_ok( ip, &operands[0], &operands[1], (struct oper *)NULL);break;
    case 3:
	    i = operand_ok( ip, &operands[0], &operands[1], &operands[2] );break;
    }
    if (i)
	PROG_ERROR(i);
    if (ip->align_i & dot) /* don't want instructions on odd bounds */
	    PROG_ERROR(E_ODDADDR);
#if AS
    if (ISINSTRUC( ip->op_i ) )
	    code_length = 2; /* all instructions at least this long */
#endif
    (ip->routine_i)(ip, numops);
#if AS
    if (code_length) {
	  put_words(code,code_length);  /* output text */
	  bc = code_length;             /* increment LC */
    }
#endif
}


static unsigned
op_to_bits( op )
    register struct oper *op;
{
    /* return the address-mode bits for operand *op */
    register unsigned s; 
    static unsigned bits[] = {
	0,
	AM_REG, AM_DEFER, AM_POSTINC, AM_PREDEC, AM_DISPL,
	AM_INDEX, AM_ABSS, AM_ABSL, AM_IMMED, AM_NORMAL, 
	AM_REGPAIR, -1, -1, -1, -1,
	AM_REGLIST,AM_FREGLIST,AM_FCREGLIST
    };
    switch ( s = bits[(int)op->type_o]){
    case AM_REG:
	s = reg_access[op->value_o]; break;
    case AM_DISPL:
	if (op->reg_o == PCREG) s = AM_PCDISPL; break;
    case AM_INDEX:
	if (op->reg_o == PCREG) s = AM_PCINDEX; break;
    }
    return s;
}

int
operand_ok( ip, op1, op2, op3 )
    struct ins_bkt *ip;
    struct oper    *op1, *op2, *op3;
{
    /*
     * this routine answers the eternal question:
     *  are operands *op1 and *op2 ok to use as the operands of instruction *ip?
     * it does it by looking at the optype_i bit fields in the instruction
     * description.
     */
    register i;
    register unsigned opbits1, opbits2, opbits3;
    register noperands = ip->noper_i;

    op1->access_o = opbits1 = op_to_bits( op1 );
    if (op2)
	op2->access_o = opbits2 = op_to_bits( op2 );
    else
	opbits2 = 0;
    if (op3)
	op3->access_o = opbits3 = op_to_bits( op3 );
    else
	opbits3 = 0;
    switch (ip->touchop_i&TOUCH2(TOUCHMASK)){
    case TOUCH2(SPEC(2)):
	/* special hackery for shifts */
	if (opbits1 == AM_IMMED && ((i=op1->value_o)<1 || i>8 || op1->sym_o))
	    return E_CONSTANT;
	break;
    } 
    switch (ip->touchop_i&TOUCH1(TOUCHMASK)){
    case TOUCH1(SPEC(0)):
    case TOUCH1(SPEC(1)):
	/* special hackery for bit ops */
	if (opbits1 == AM_IMMED){
	    i = op1->value_o;
	    if (op1->sym_o) return E_CONSTANT;
	    if (opbits2 == AM_DREG){
		if (i < 0 || i > 31 ) return E_CONSTANT;
	    } else 
		if (i < 0 || i > 7 ) return E_CONSTANT;
	}
	break;
    }
    switch (noperands){
    case 0: return 0;
    case 1:
	for (i=0; i<N_OPTYPES; i+=1)
	    if (opbits1&ip->optype_i[i]) return 0;
	break;
    case 2:
	for (i=0; i<N_OPTYPES; i+=2)
	    if ((opbits1&ip->optype_i[i]) && (opbits2&ip->optype_i[i+1]) ) return 0;
	break;
    case 3:
	for (i=0; i<N_OPTYPES; i+=3)
	    if ((opbits1&ip->optype_i[i]) && (opbits2&ip->optype_i[i+1]) && (opbits3&ip->optype_i[i+2]) ) return 0;
	break;
    }
    return E_OPERAND;
}


/* table used to determine node type. */
/* 
 * we would really like this table to be subscripted by the enumerated type
 * opcode_t, but C cannot hack that. Order here is VERY IMPORTANT,
 * and this table must change if the opcode order or number changes!!
 */
char opcodetypes[] = {
	0, 0, 0,			/* FIRST, COMMENT, LABEL */
	PSEUDOCODE, PSEUDOCODE, 	/* LONG, WORD */
	PSEUDOCODE, PSEUDONOCODE,	/* BYTE,TEXT */
	PSEUDONOCODE, PSEUDONOCODE,	/* DATA, DATA1 */
	PSEUDONOCODE, PSEUDONOCODE,	/* DATA2, BSS */
	PSEUDONOCODE,			/* PROC */
	PSEUDONOCODE, PSEUDONOCODE,	/* GLOBL, COMM */
	PSEUDOCODE, PSEUDOCODE, 	/* EVEN, ALIGN */
	PSEUDOCODE, PSEUDOCODE, 	/* ASCIZ, ASCII */
	PSEUDOCODE, PSEUDOCODE, 	/* FLOAT, DOUBLE */
	PSEUDONOCODE,			/* STABS */
	PSEUDONOCODE, PSEUDONOCODE,	/* STABD, STABN */
	PSEUDOCODE, PSEUDONOCODE,	/* SKIP, LCOMM */
	PSEUDONOCODE,			/* CPID */
	INSTRTYPE, INSTRTYPE,		/* CSWITCH, FSWITCH */
	INSTRTYPE, INSTRTYPE,		/* BRANCH, MOVE */
	INSTRTYPE, INSTRTYPE,		/* MOVEM, EXIT */
	INSTRTYPE, INSTRTYPE,		/* DBRA, CALL */
	INSTRTYPE, INSTRTYPE,		/* JUMP, DJMP */
	INSTRTYPE, INSTRTYPE,		/* LINK, CMP */
	INSTRTYPE, INSTRTYPE,		/* PEA, ADD */
	INSTRTYPE, INSTRTYPE,		/* AND, EXT */
	INSTRTYPE, INSTRTYPE,		/* OR, TST */
	INSTRTYPE, INSTRTYPE,		/* ASL, ASR */
	INSTRTYPE, INSTRTYPE,		/* SUB, UNLK */
	INSTRTYPE, INSTRTYPE,		/* LEA, CLR */
	INSTRTYPE, INSTRTYPE,		/* BOP, EOR */
	INSTRTYPE,           		/* OTHER */
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.