home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d1xx
/
d186
/
a68k.lha
/
A68k
/
Operands.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-02-26
|
17KB
|
558 lines
/*------------------------------------------------------------------*/
/* */
/* MC68000 Cross Assembler */
/* */
/* Copyright (c) 1985 by Brian R. Anderson */
/* */
/* Operand processor - January 10, 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(), Instructions(), ObjDir();
extern int ReadSymTab(), OpenIncl(), CountNest();
extern long AddrBndW(), AddrBndL(), GetValue(), CalcValue();
extern char *AddName(), *GetField();
extern struct SymTab *NextSym();
extern struct SymTab **HashIt();
int GetArgs(), GetAReg(), GetInstModeSize(), GetMultReg();
int GetArgs (name) char *name;
/* Gets macro arguments and adds them to FNStack after adding "name".
Returns the number of arguments added to the stack.
Note that this might not be the full number of arguments
provided if the stack overflowed. */
{
register char *s, *t;
int narg, instring;
char currarg[MAXLINE]; /* Current argument */
narg = strlen (name) + 1;
Heap2Space (narg); /* Find space for name */
strcpy (NextFNS, name); /* Add name to stack */
NextFNS += narg; /* Bump pointer */
if (NextFNS > High2)
High2 = NextFNS; /* Update high-water mark */
narg = 0; /* Argument counter */
s = Line + SrcLoc; /* Now scan Line */
while (!isspace(*s) && (*s != ';') && (*s != '\0')) {
t = currarg;
if (instring = (*s == '<')) /* String delimiter */
s++;
while (1) {
if (*s == '\0')
break; /* End of line */
if (instring) {
if (*s == '>') {
s++;
break; /* End of string */
}
} else {
if ((*s == ',') /* End of operand */
|| isspace(*s) /* End of all operands */
|| (*s == ';')) /* Start of comments */
break;
}
*t++ = *s++; /* Get a character */
}
*t++ = '\0';
Heap2Space (t - currarg); /* Check for space */
strcpy (NextFNS, currarg); /* Store argument */
NextFNS += t - currarg; /* Next available space */
if (NextFNS > High2)
High2 = NextFNS; /* High-water mark */
narg++; /* Count arguments */
if (*s == ',')
s++; /* Skip over separator */
}
return (narg); /* Successful completion */
}
EffAdr (EA, Bad) register struct OpConfig *EA; int Bad;
/* Adds effective address field to Op (BITSET representing opcode) */
{
if ((1 << (EA->Mode - 1)) IN Bad) {
Error (EA->Loc, ModeErr); /* Invalid mode */
return;
} else if (EA->Mode > 12) /* Special modes */
return;
else if (EA->Mode < 8) /* Register direct or indirect */
Op |= ((EA->Mode - 1) << 3) | EA->Rn;
else
Op |= 0x0038 | (EA->Mode - 8); /* Absolute modes */
OperExt (EA);
}
OperExt (EA) register struct OpConfig *EA;
/* Calculate operand Extension word, and check range of operands */
{
switch (EA->Mode) {
case AbsL:
break; /* No range checking needed */
case AbsW:
case ARDisp:
case PCDisp:
if ((EA->Value < -32768) || (EA->Value > 32767))
Error (EA->Loc, SizeErr);
break;
case ARDisX:
case PCDisX:
if ((EA->Value < -128) || (EA->Value > 127))
Error (EA->Loc, SizeErr);
EA->Value &= 0x00FF; /* Displacement */
EA->Value |= EA->Xn << 12; /* Index reg. */
if (EA->X == Areg) EA->Value |= 0x8000; /* Addr. Reg. */
if (EA->Xsize == Long) EA->Value |= 0x0800; /* Long reg. */
break;
case Imm:
if (Size == Word) {
if ((EA->Value < -32768) || (EA->Value > 65535L))
Error (EA->Loc, SizeErr);
} else if (Size == Byte)
if ((EA->Value < -128) || (EA->Value > 255))
Error (EA->Loc, SizeErr);
break;
}
}
GetOperand (oper, op, pcconv)
char *oper; register struct OpConfig *op; int pcconv;
/* Finds mode and value for source or destination operand.
If PC-relative addressing is permitted, "pcconv" gives the
offset to the displacement word; otherwise "pcconv" is zero. */
{
register char *s, *t;
register int i;
char *opend;
char UCoper[MAXLINE], tempop[MAXLINE];
int rloc;
long templong;
op->Value = op->Defn = 0;
op->Mode = Null;
op->X = X0;
op->Hunk = ABSHUNK;
if (*oper == '\0')
return; /* Nothing to process */
s = oper;
t = UCoper;
while (*t++ = toupper (*s++)) /* Upper-case version */
;
opend = s - 2; /* Last character of operand */
if (*oper == '#') { /* Immediate */
op->Value = GetValue (oper+1, (op->Loc)+1);
op->Mode = Imm;
op->Hunk = Hunk2;
op->Defn = DefLine2;
return;
}
i = IsRegister (oper, opend-oper+1);
if (i >= 0) {
op->Mode = (i & 8) ? ARDir : DReg; /* Register type */
op->Rn = i & 7; /* Register number */
return;
} else if (i == -2) {
op->Mode = MultiM; /* Equated register list */
op->Value = Sym->Val;
return;
} else if ((*oper == '(') && (*opend == ')')) {
i = IsRegister (oper+1, opend-oper-1);
if (i >= 8 && i <= 15) {
op->Mode = ARInd; /* Address Register indirect */
op->Rn = i - 8;
return;
} else if (i != -1) {
Error (op->Loc, AddrErr); /* Data register is invalid */
return;
} /* else may be parenthesized expression */
} else if ((*oper == '(') /* Post-increment */
&& (*opend == '+')
&& (*(opend-1) == ')')) {
op->Mode = ARPost;
op->Rn = GetAReg (oper+1, opend-oper-2, op->Loc + 1);
return;
} else if ((*oper == '-') /* Pre-decrement */
&& (*opend == ')')
&& (*(oper+1) == '(')) {
i = IsRegister (oper+2, opend-oper-2);
if (i >= 8 && i <= 15) {
op->Mode = ARPre;
op->Rn = i - 8;
return;
} else if (i > 0) {
Error (op->Loc, AddrErr); /* Data register is invalid */
return;
} /* else parenthesized expression with leading minus? */
} else if (strcmp (UCoper, "SR") == 0) {
op->Mode = SR; /* Status Register */
return;
} else if (strcmp (UCoper, "CCR") == 0) {
op->Mode = CCR; /* Condition Code Register */
return;
} else if (strcmp (UCoper, "USP") == 0) {
op->Mode = USP; /* User Stack Pointer */
return;
}
/* Try to split off displacement (if present).
We'll assume we have a register expression if the operand
ends with a parenthesized expression not preceded by an
operator. I know this code is a real kludge, but that's
the result of the bloody syntax. Thanks, Motorola. */
s = opend; /* Last character */
if (i = (*s == ')')) /* Trailing parenthesis? */
while (*(--s) != '(') /* Find left parenthesis */
if (s <= oper)
break;
if (s <= oper) /* Must not be at beginning */
i = FALSE;
if (i) {
if (s == (oper+1)) {
if (*oper == '-')
i = FALSE; /* Leading minus sign */
} else {
t = s - 1;
if (*t == '*') { /* Location counter? */
t--;
if (!IsOperator (t) || (*t == ')'))
i = FALSE; /* No, it's multiplication */
} else if (IsOperator (t) && (*t != ')')) {
i = FALSE; /* Preceded by an operator */
}
}
}
if (i) { /* Looks like a displacement mode */
*s = '\0';
op->Value = GetValue (oper, op->Loc); /* Displacement */
op->Hunk = Hunk2; /* Hunk number */
op->Defn = DefLine2; /* Line where defined */
*s++ = '('; /* Restore parenthesis */
rloc = op->Loc + s - oper; /* The register starts here */
s = GetField (s, tempop); /* Get address register */
if (*s == '\0') /* If there's no index register */
tempop[strlen(tempop)-1] = '\0'; /* chop parenthesis */
if ((tempop[2] == '\0')
&& (toupper (tempop[0]) == 'P')
&& (toupper (tempop[1]) == 'C')) {
op->Mode = PCDisp; /* Program Counter */
if (op->Hunk == CurrHunk) {
op->Value -= (AddrCnt+pcconv); /* Adjust displacement */
op->Hunk = ABSHUNK;
}
} else {
if ((op->Value == 0) /* If displacement is zero */
&& (op->Hunk == ABSHUNK) /* and is absolute */
&& (op->Defn < LineCount) /* and is already defined */
&& !(OpM68R IN AdrModeA)) /* and isn't for a MOVEP */
op->Mode = ARInd; /* forget the displacement. */
else
op->Mode = ARDisp; /* Address reg. w/displacement */
op->Rn = GetAReg (tempop, strlen (tempop), rloc);
}
if (*s != '\0') { /* Index register is present */
if (op->Mode == PCDisp)
op->Mode = PCDisX; /* Program Counter indexed */
else
op->Mode = ARDisX; /* Address Register indexed */
if (*s != ',')
Error (op->Loc, AddrErr); /* Bad separator */
s++; /* Skip separator */
rloc = op->Loc + s - oper; /* Start of index */
s = GetField (s, tempop); /* Get index register */
t = tempop + strlen(tempop);
if (*s == '\0')
*(--t) = '\0'; /* Chop parenthesis */
else
Error (rloc, AddrErr); /* It better be there */
t -= 2;
if ((t < tempop) || (*t != '.')) {
op->Xsize = Word; /* Size defaults to 16 bits */
t += 3;
} else {
*t++ = '\0'; /* Chop off size code */
switch (toupper (*t)) {
case 'W': /* Word */
op->Xsize = Word;
break;
case 'L': /* Long */
op->Xsize = Long;
break;
default:
Error (op->Loc+s-1-oper, SizeErr); /* Invalid size */
op->Xsize = Word; /* Make it word for now */
}
}
i = IsRegister (tempop,t-tempop-1); /* Get register */
op->Xn = i & 7; /* Index register number */
if ((i >= 0) && (i <= 7))
op->X = Dreg; /* Data Register */
else if ((i >= 8) && (i <= 15))
op->X = Areg; /* Address Register */
else
Error (rloc, AddrErr); /* Invalid register */
}
if ((op->Hunk >= 0) && (op->Hunk != ABSHUNK))
Error (op->Loc, RelErr); /* Relocatable displacement */
return;
}
if ((i = GetMultReg (oper, op->Loc)) != 0) {
op->Value = (long) i;
op->Mode = MultiM; /* Register list for MOVEM */
return;
}
op->Value = GetValue (oper, op->Loc); /* Get operand value */
op->Hunk = Hunk2;
op->Defn = DefLine2;
op->Mode = AbsL; /* Assume absolute long addressing */
if (DefLine2 < LineCount) { /* Backward reference */
if (Hunk2 < 0) {
return; /* External - leave as absolute long */
} else if (Hunk2 == CurrHunk) { /* Reference to current hunk */
if (pcconv) {
templong = op->Value-(AddrCnt+pcconv); /* PC disp. */
if ((templong >= -32768) && (templong <= 32767)) {
op->Mode = PCDisp; /* Convert to PC relative mode */
op->Value=templong; /* Adjust displacement */
op->Hunk = ABSHUNK;
}
}
} else if (Hunk2 == ABSHUNK) { /* Absolute value */
if ((op->Value >= -32768) && (op->Value <= 32767))
op->Mode = AbsW; /* Absolute word */
} else if (SmallData && (op->Value>=0) && (op->Value<=65535L)) {
op->Mode = ARDisp; /* Make it a data reference */
op->Rn = 4; /* through register A4 */
op->Value -= 32768L; /* Adjust displacement */
op->Hunk = ABSHUNK;
}
return; /* Could default to absolute long */
} else if (!SmallData) { /* Fwd. reference - if not small data */
return; /* leave as absolute long addressing */
} else if (!Pass2) { /* Forward reference, pass 1 */
op->Mode = ARDisp; /* Assume displacement */
op->Rn = 4; /* from register A4 */
op->Hunk = ABSHUNK;
return;
} else { /* On pass 2 we know what it is */
if (Hunk2 < 0) {
Error (op->Loc,FwdRef); /* External - must be 32 bits */
op->Mode = AbsW; /* Force absolute word anyway */
} else if (Hunk2 == CurrHunk) { /* It's in the current hunk */
op->Mode = PCDisp; /* Convert to PC relative mode */
op->Value -= AddrCnt + pcconv; /* Adjust displacement */
op->Hunk = ABSHUNK;
if (!pcconv || (op->Value < -32768) || (op->Value > 32767))
Error (op->Loc,FwdRef); /* It doesn't fit! */
} else if (Hunk2 == ABSHUNK) { /* It's absolute */
op->Mode = AbsW; /* It has to fit in a word */
if ((op->Value < -32768) || (op->Value > 32767))
Error (op->Loc,FwdRef); /* It doesn't fit! */
} else {
op->Mode = ARDisp; /* Assume data reference */
op->Rn = 4; /* through register A4 */
op->Value -= 32768L; /* Adjust displacement */
if ((op->Value < -32768) || (op->Value > 32767))
Error (op->Loc,FwdRef); /* It doesn't fit! */
}
}
}
int GetMultReg (oper, loc) char *oper; int loc;
/* Builds a register mask for the MOVEM instruction.
Returns the mask in the low-order portion of its value if
"oper" is a valid multiple-register list; otherwise returns 0. */
{
register char *s, *t;
register int j;
int t1, t2; /* Temporary variables for registers */
int range; /* We're processing a range of registers */
int multext; /* The result is built here */
multext = 0;
range = FALSE;
s = oper;
if (IsOperator (s))
return (0); /* Starts with an operator! */
while (1) {
for (t = s; *t; t++) {
if ((*t == '-') || (*t == '/')) {
break;
}
}
if ((multext == 0) && (*t == '\0'))
return (0); /* Reject single term */
if ((t2 = IsRegister (s, t-s)) < 0)
return (0); /* Not a recognizable register */
if (!range) {
multext |= (1 << t2); /* Single register */
t1 = t2; /* Save number in case it's a range */
} else { /* Range of registers */
range = FALSE;
if (t1 > t2) {
j = t1; /* Swap registers if backwards */
t1 = t2;
t2 = j;
}
for (j = t1; j <= t2; j++)
multext |= (1 << j); /* Mark all registers in range */
if (*t == '-')
return (0); /* Invalid range */
}
if (*t == '\0')
break; /* Normal end of operand */
if (*t++ == '-')
range = TRUE; /* Range indicator */
if (*t == '\0')
return (0); /* Premature end of operand */
s = t;
}
return (multext);
}
int GetAReg (op, len, loc) char *op; int len, loc;
/* Validate an address register specification.
Valid specifications are A0 through A7 , SP, or an EQUR label.
The address register number will be returned if it is valid.
Otherwise, Error will be called, using "loc" for the error
location (this is its only use), and zero (A0) will be returned. */
{
register int i;
i = IsRegister (op, len); /* Get register number */
if ((i >= 8) && (i <= 15))
return (i - 8); /* Valid address register */
else {
Error (loc, AddrErr); /* Not an address register */
return (0); /* Set to A0 */
}
}
int IsRegister (op, len) char *op; int len;
/* Check whether the current operand is an address or data register.
Valid specifications are D0 throuth D7, A0 through A7, SP,
or any symbol equated to a register with the EQUR directive.
Return values:
0 through 7 - data registers 0 through 7 respectively
8 through 15 - address registers 0 through 7 respectively
-1 - not a recognizable register
-2 - Equated register list for MOVEM instruction (REG) */
{
char tempop[MAXLINE];
register char *s;
register int i;
if (len == 2) { /* Two-character specification */
i = toupper (*op);
s = op + 1;
if ((i == 'S') && (toupper (*s) == 'P')) {
return (15); /* Stack Pointer */
} else if ((*s >= '0') && (*s <= '7')) {
if (i == 'A') {
return (*s - '0' + 8); /* Address Register */
} else if (i == 'D') {
return (*s - '0'); /* Data Register */
}
}
}
if (!GotEqur) /* If we have no EQURs to check */
return (-1); /* don't waste any time here. */
for (i = 0, s = op; i < len; i++) {
if (IsOperator (s))
return (-1); /* It sure isn't a label */
tempop[i] = *s++;
}
tempop[i] = '\0';
if (ReadSymTab (tempop)) {
if (Sym->Flags & 0x60) {
AddRef (LineCount); /* Found a register or list */
return ((Sym->Flags & 0x20) ? (int) Sym->Val : -2);
}
}
return (-1); /* Not a recognizable register */
}
int GetInstModeSize (Mode) register int Mode;
/* Determines the size for the various instruction modes. */
{
switch (Mode) {
case ARDisp:
case ARDisX:
case PCDisp:
case PCDisX:
case AbsW:
return (2);
case AbsL:
return (4);
case MultiM:
return (0); /* Accounted for by code generator */
case Imm:
if (Size == Long)
return (4);
else
return (2);
default:
return (0);
}
}