Example #1
0
static void SetUseChgInfo (CodeEntry* E, const OPCDesc* D)
/* Set the Use and Chg in E */
{
    const ZPInfo* Info;

    /* If this is a subroutine call, or a jump to an external function,
    ** lookup the information about this function and use it. The jump itself
    ** does not change any registers, so we don't need to use the data from D.
    */
    if ((E->Info & (OF_UBRA | OF_CALL)) != 0 && E->JumpTo == 0) {
        /* A subroutine call or jump to external symbol (function exit) */
        GetFuncInfo (E->Arg, &E->Use, &E->Chg);
    } else {
        /* Some other instruction. Use the values from the opcode description
        ** plus addressing mode info.
        */
        E->Use = D->Use | GetAMUseInfo (E->AM);
        E->Chg = D->Chg;

        /* Check for special zero page registers used */
        switch (E->AM) {

            case AM65_ACC:
                if (E->OPC == OP65_ASL || E->OPC == OP65_DEC ||
                    E->OPC == OP65_INC || E->OPC == OP65_LSR ||
                    E->OPC == OP65_ROL || E->OPC == OP65_ROR) {
                    /* A is changed by these insns */
                    E->Chg |= REG_A;
                }
                break;

            case AM65_ZP:
            case AM65_ABS:
            /* Be conservative: */
            case AM65_ZPX:
            case AM65_ABSX:
            case AM65_ABSY:
                Info = GetZPInfo (E->Arg);
                if (Info && Info->ByteUse != REG_NONE) {
                    if (E->OPC == OP65_ASL || E->OPC == OP65_DEC ||
                        E->OPC == OP65_INC || E->OPC == OP65_LSR ||
                        E->OPC == OP65_ROL || E->OPC == OP65_ROR ||
                        E->OPC == OP65_TRB || E->OPC == OP65_TSB) {
                        /* The zp loc is both, input and output */
                        E->Chg |= Info->ByteUse;
                        E->Use |= Info->ByteUse;
                    } else if ((E->Info & OF_STORE) != 0) {
                        /* Just output */
                        E->Chg |= Info->ByteUse;
                    } else {
                        /* Input only */
                        E->Use |= Info->ByteUse;
                    }
                }
                break;

            case AM65_ZPX_IND:
            case AM65_ZP_INDY:
            case AM65_ZP_IND:
                Info = GetZPInfo (E->Arg);
                if (Info && Info->ByteUse != REG_NONE) {
                    /* These addressing modes will never change the zp loc */
                    E->Use |= Info->WordUse;
                }
                break;

            default:
                /* Keep gcc silent */
                break;
        }
    }
}
Example #2
0
static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
/* Parse an instruction nnd generate a code entry from it. If the line contains
 * errors, output an error message and return NULL.
 * For simplicity, we don't accept the broad range of input a "real" assembler
 * does. The instruction and the argument are expected to be separated by
 * white space, for example.
 */
{
    char                Mnemo[IDENTSIZE+10];
    const OPCDesc* 	OPC;
    am_t      	   	AM = 0;	       	/* Initialize to keep gcc silent */
    char                Arg[IDENTSIZE+10];
    char      	      	Reg;
    CodeEntry*	     	E;
    CodeLabel*	   	Label;

    /* Read the first token and skip white space after it */
    L = SkipSpace (ReadToken (L, " \t:", Mnemo, sizeof (Mnemo)));

    /* Check if we have a label */
    if (*L == ':') {

	/* Skip the colon and following white space */
	L = SkipSpace (L+1);

	/* Add the label */
	CS_AddLabel (S,	Mnemo);

	/* If we have reached end of line, bail out, otherwise a mnemonic
	 * may follow.
	 */
	if (*L == '\0') {
	    return 0;
	}

	L = SkipSpace (ReadToken (L, " \t", Mnemo, sizeof (Mnemo)));
    }

    /* Try to find the opcode description for the mnemonic */
    OPC = FindOP65 (Mnemo);

    /* If we didn't find the opcode, print an error and bail out */
    if (OPC == 0) {
	Error ("ASM code error: %s is not a valid mnemonic", Mnemo);
	return 0;
    }

    /* Get the addressing mode */
    Arg[0] = '\0';
    switch (*L) {

	case '\0':
	    /* Implicit or accu */
            if (OPC->Info & OF_NOIMP) {
                AM = AM65_ACC;
            } else {
                AM = AM65_IMP;
            }
	    break;

	case '#':
	    /* Immidiate */
	    StrCopy (Arg, sizeof (Arg), L+1);
	    AM = AM65_IMM;
	    break;

	case '(':
	    /* Indirect */
	    L = ReadToken (L+1, ",)", Arg, sizeof (Arg));

	    /* Check for errors */
   	    if (*L == '\0') {
	     	Error ("ASM code error: syntax error");
	     	return 0;
	    }

	    /* Check the different indirect modes */
       	    if (*L == ',') {
	     	/* Expect zp x indirect */
	     	L = SkipSpace (L+1);
	     	if (toupper (*L) != 'X') {
	     	    Error ("ASM code error: `X' expected");
	     	    return 0;
	     	}
	     	L = SkipSpace (L+1);
	     	if (*L != ')') {
	     	    Error ("ASM code error: `)' expected");
	     	    return 0;
	     	}
	     	L = SkipSpace (L+1);
	      	if (*L != '\0') {
	     	    Error ("ASM code error: syntax error");
	     	    return 0;
	     	}
	     	AM = AM65_ZPX_IND;
	    } else if (*L == ')') {
	     	/* zp indirect or zp indirect, y */
	     	L = SkipSpace (L+1);
	      	if (*L == ',') {
	     	    L = SkipSpace (L+1);
	     	    if (toupper (*L) != 'Y') {
	     	      	Error ("ASM code error: `Y' expected");
	     	      	return 0;
	     	    }
	     	    L = SkipSpace (L+1);
	     	    if (*L != '\0') {
	       	       	Error ("ASM code error: syntax error");
	     	      	return 0;
	     	    }
	     	    AM = AM65_ZP_INDY;
	     	} else if (*L == '\0') {
	     	    AM = AM65_ZP_IND;
	     	} else {
	     	    Error ("ASM code error: syntax error");
   	     	    return 0;
	     	}
	    }
	    break;

	case 'a':
       	case 'A':
	    /* Accumulator? */
	    if (L[1] == '\0') {
	     	AM = AM65_ACC;
	     	break;
	    }
	    /* FALLTHROUGH */

	default:
	    /* Absolute, maybe indexed */
	    L = ReadToken (L, ",", Arg, sizeof (Arg));
	    if (*L == '\0') {
	     	/* Absolute, zeropage or branch */
	      	if ((OPC->Info & OF_BRA) != 0) {
		    /* Branch */
		    AM = AM65_BRA;
		} else if (GetZPInfo(Arg) != 0) {
		    AM = AM65_ZP;
		} else {
                    /* Check for subroutine call to local label */
                    if ((OPC->Info & OF_CALL) && IsLocalLabelName (Arg)) {
                        Error ("ASM code error: "
                               "Cannot use local label `%s' in subroutine call",
                               Arg);
                    }
		    AM = AM65_ABS;
		}
	    } else if (*L == ',') {
		/* Indexed */
		L = SkipSpace (L+1);
		if (*L == '\0') {
      		    Error ("ASM code error: syntax error");
		    return 0;
		} else {
	      	    Reg = toupper (*L);
		    L = SkipSpace (L+1);
		    if (Reg == 'X') {
		      	if (GetZPInfo(Arg) != 0) {
		      	    AM = AM65_ZPX;
		      	} else {
		      	    AM = AM65_ABSX;
	    	      	}
		    } else if (Reg == 'Y') {
   		      	AM = AM65_ABSY;
		    } else {
		       	Error ("ASM code error: syntax error");
	       	       	return 0;
		    }
		    if (*L != '\0') {
	    	       	Error ("ASM code error: syntax error");
	    	       	return 0;
	    	    }
	    	}
	    }
	    break;

    }

    /* If the instruction is a branch, check for the label and generate it
     * if it does not exist. This may lead to unused labels (if the label
     * is actually an external one) which are removed by the CS_MergeLabels
     * function later.
     */
    Label = 0;
    if (AM == AM65_BRA) {

	/* Generate the hash over the label, then search for the label */
	unsigned Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
	Label = CS_FindLabel (S, Arg, Hash);

	/* If we don't have the label, it's a forward ref - create it */
	if (Label == 0) {
	    /* Generate a new label */
	    Label = CS_NewCodeLabel (S, Arg, Hash);
	}
    }

    /* We do now have the addressing mode in AM. Allocate a new CodeEntry
     * structure and initialize it.
     */
    E = NewCodeEntry (OPC->OPC, AM, Arg, Label, LI);

    /* Return the new code entry */
    return E;
}