Files
Arquivotheca.SunOS-4.1.4/usr.etc/gp/as/assemble.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

1476 lines
35 KiB
C

#ifndef lint
static char sccsid[] = "@(#)assemble.c 1.1 94/10/31 SMI";
#endif
/* Microassembler instruction builder */
#include <stdio.h>
#include "micro.h"
#define CHKRNG(x) if(x<0){ error("RAM address %d out of range", x); return; }
#define COUNT_OPERANDS(x,y,z) if (z<x||z>y){ if (x==y) error("Expected %d operands, got %d", x,z); else error("Expected %d to %d operands, got %d", x,y,z); return;}
#define SRCDST_DEFAULT 0
#define NO (-100)
extern NODE n[NNODE + 1];
extern NODE *curnode;
extern int curlineno;
extern int curaddr;
extern char *curfilename;
extern char *curline;
#ifdef VIEW
extern Boolean aflt();
short srcdesttab[9][14] =
/* a s f f n l b s p f f f f f */
/* m h p p r e r h r i p p p l */
/* m r r e d r m o f a b d 1 */
/* e e e g r e e m o p p p r */
/* m g g e g m p 1 e */
/* p h l g p g */
/*am */ {{ 7, 10, 11, 11, 3, 2, 8, 15, 9, 6, 12, 13, 14, 5 },
/*shmem */ { 23, -1, 27, 27, -1, -1, 24, 31, 25, 22, 28, 29, 30, -1 },
/*fpregh */ { 55, 58, 59, -1, -1, -1, 56, 63, 57, 54, 60, 61, 62, -1 },
/*fpregl */ { 55, 58, -1, 59, -1, -1, 56, 63, 57, 54, 60, 61, 62, -1 },
/*fifo2 */ { 17, -1, -1, -1, -1, -1, 18, 21, 19, -1, -1, -1, -1, -1 },
/*fpstreg */ { 49, 50, 51, 51, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
/*prom */ { 33, 34, 35, 35, -1, -1, -1, -1, -1, 32, -1, -1, -1, -1 },
/*swfl2reg*/ { 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 },
/*GENERAL */ { 39, 42, 43, 43, -1, -1, 40, 47, 41, 38, 44, 45, 46, 37 }};
#endif
#ifdef PAINT
short srcdesttab[20][10] =
/* a s f z v p v m f G */
/* m c i b r p s u l E */
/* r f r d p t l 1 N */
/* m o d r r r r r E */
/* e 1 r e o e e e R */
/* m e g m g s g A */
/* g L */
/*am */ {{ 9, 89, 97, 33, 57, 25, 65,121, 1, 73},
/*scrmem */ { 10, -1, -1, -1, -1, 26, 66,122, -1, 74},
/*nreg */ { 3, -1, -1, -1, -1, -1, -1, -1, -1, -1},
/*stlreg */ { 2, -1, -1, -1, -1, -1, -1, -1, -1, -1},
/*brreg */ { 4,116,100, 36, -1, -1, -1, -1, -1, 68},
/*scrmemp*/ { 5,117,101, 37, -1, -1, -1, -1, -1, 69},
/*pppromp*/ { 7, -1,103, 39, -1, -1, -1, -1, -1, 71},
/*fifo2 */ { 8, 88, -1, -1, -1, 24, 64,120, -1, 72},
/*fl2reg */ { 6, -1, -1, -1, -1, -1, -1, -1, -1, 70},
/*zbwdreg*/ { 11, 91, -1, -1, -1, 27, 67,123, -1, 75},
/*vwdreg */ { 13, 93, -1, -1, 61, 29, -1,125, -1, 77},
/*mulx */ { 14, 94, -1, -1, 62, 30, -1,126, -1, 78},
/*muly */ { 15, 95, -1, -1, 63, 31, -1,127, -1, 79},
/*mulmode*/ { 16,112, -1, -1, -1, -1, -1, -1, -1, 80},
/*iidreg */ { 17,113, -1, -1, -1, -1, -1, -1, -1, 81},
/*vhiareg*/ { 18,114, 98, 34, -1, -1, -1, -1, -1, 82},
/*vloareg*/ { 19,115, 99, 35, -1, -1, -1, -1, -1, 83},
/*vctlreg*/ { 20, -1, -1, -1, -1, -1, -1, -1, -1, 84},
/*zbhiptr*/ { 22,118, -1, -1, -1, -1, -1, -1, -1, 86},
/*zbloptr*/ { 23,119, -1, -1, -1, -1, -1, -1, -1, 87}};
#endif
void
init_one(i)
short i;
{
n[i].filename = 0;
n[i].word1 = 0x2800;
n[i].word2 = 0;
n[i].word3 = 0;
n[i].word4 = 0;
n[i].symptr = 0;
n[i].lineno = 0;
n[i].line = 0;
n[i].sccsid = False;
n[i].filled = False;
n[i].org_pseudo = False;
n[i].dreg_opd = False;
n[i].has_genl = False;
n[i].genl_sym = False;
n[i].imm_sym = False;
n[i].imm_29116 = False;
#ifdef VIEW
n[i].fp_used = False;
n[i].no_fpstore = False;
n[i].no_shmread = False;
n[i].no_shminc = False;
n[i].no_fpinc = False;
n[i].fphilo = NOTFP;
#endif
#ifdef PAINT
n[i].no_scrmread = False;
n[i].no_scrminc = False;
n[i].three_way = False;
#endif
n[i].no_flag = False;
n[i].status = False;
}
init_assm()
{
short i;
for (i = 0; i <= 3; i++) {
init_one(i);
}
}
copyfill(p1, p2)
register NODE *p1;
register NODE *p2;
{
p2->status = p1->status;
p2->symptr = p1->symptr;
p2->imm_29116 = p1->imm_29116;
p2->imm_sym = p1->imm_sym;
p2->no_promread = p1->no_promread;
#ifdef VIEW
p2->word1 = p1->word1;
p2->word2 = p1->word2;
p2->word3 = p1->word3;
p2->word4 = p1->word4;
p2->fp_used = p1->fp_used;
p2->fphilo = p1->fphilo;
p2->no_fpstore = p1->no_fpstore;
p2->no_fpinc = p1->no_fpinc;
p2->no_shmread = p1->no_shmread;
p2->no_shminc = p1->no_shminc;
#endif
#ifdef PAINT
p2->no_scrmread = p1->no_scrmread;
p2->no_scrminc = p1->no_scrminc;
#endif
}
anext()
{
register NODE *rp;
int i;
/* if (!curnode->filled) { copyfill(curnode+2,curnode+3);
* copyfill(curnode+1,curnode+2); (curnode+1)->fp_used =
* curnode->fp_used; } */
rp = ++curnode;
if (curnode - n + 4 < NNODE) {
init_one(curnode - n + 4);
}
if (curnode >= &n[NNODE]) {
fatal("too many instructions!");
}
rp->filename = curfilename;
rp->lineno = curlineno;
rp->line = curline;
}
anop()
{
#ifdef VIEW
Boolean bool;
#endif
curnode->filled = True;
curnode->word1 = 0x280e;
if (!curnode->imm_29116) {
curnode->word2 = 0x71;
curnode->word3 |= 0x4000;
}
#ifdef VIEW
bool = aflt(0, 0, 0, 0, 0);
#endif
}
adebug(dsw)
int dsw;
{
curnode->word4 |= dsw << 6;
}
astop()
{
curnode->word4 |= 0x20;
}
abkpt()
{
curnode->word4 |= 0x10;
}
astatus()
{
if (curnode->status) {
curnode->word1 &= 0xdfff;
}
}
assemble(rp, sc, nop, op)
RESERVED *rp;
int nop,
sc;
OPERAND *op;
{
curnode->filled = True;
(rp->kracker) (rp, nop, op);
if (sc == 1) {
if ((curnode + 1)->imm_29116) {
(curnode + 1)->status = True;
} else {
curnode->word1 &= 0xdfff;
}
}
}
sor(rp, nop, op)
register RESERVED *rp;
int nop;
register OPERAND *op;
{
/* move-like instructions -- type (quadrant) depends on the operands */
unsigned short bits;
int quad;
struct sym *sp;
int a,
b,
c;
COUNT_OPERANDS(2, 2, nop);
if (op->r == D) {
curnode->no_flag = True;
}
if (op->r == RAM) {
static short ramsrc[] =
{NO, NO, 11, 2, NO, NO, 3, NO, NO, 0, NO, NO};
quad = 2;
b = op->v;
CHKRNG(b);
a = ramsrc[(op + 1)->r];
if ((op + 1)->r == RAM && (op + 1)->v != b) {
c = (op + 1)->v;
if ((b & 0x10) != (c & 0x10)) {
error("r[%d] and r[%d] not in same half of ram", b, c);
return;
}
curnode->dreg_opd = True;
}
} else if ((op + 1)->r == RAM) {
static short ramdst[] =
{8, 6, NO, NO, 9, 10, NO, NO, 7, 4, NO, 7};
quad = 2;
b = (op + 1)->v;
CHKRNG(b);
a = ramdst[op->r];
} else {
static short movsrc[] =
{8, 6, NO, NO, 9, 10, NO, NO, 7, 4, NO, 7};
static short movdst[] =
{NO, NO, NO, 0, NO, NO, 4, 5, NO, 1, NO, NO};
quad = 3;
a = movsrc[op->r];
if (op->r == Z && op->v != 0)
goto botch;
b = movdst[(op + 1)->r];
}
if (a < 0 || b < 0) {
botch:
error("Incompatible operands");
return;
}
/* assemble the instruction */
bits = (rp->value1 << 15) | (rp->value2 << 9);
bits |= (quad << 13) | (a << 5) | b;
curnode->word2 |= bits >> 8;
curnode->word3 |= bits << 8;
if (curnode->dreg_opd) {
curnode->word2 |= (c & 0xf) << 8;
curnode->word1 &= 0xf7ff;
}
if (op->r == IMM) {
(curnode + 1)->word2 |= (op->v >> 8) & 0xff;
(curnode + 1)->word3 |= op->v << 8;
(curnode + 1)->imm_29116 = True;
} else if (op->r == SYM) {
if ((sp = lookup(op->v)) == 0) {
sp = enter(op->v);
}
(curnode + 1)->symptr = sp;
(curnode + 1)->imm_sym = True;
}
DEBUG("Sor: b/w=%d, quad=%d, op=%x, a=%x, b=%x\n", rp->value1, quad, rp->value2, a, b);
}
tor(rp, nop, op)
register RESERVED *rp;
int nop;
register OPERAND *op;
{
/* two-operand instructions -- type (quadrant) depends on the operands */
unsigned short bits;
int quad;
int a,
b,
c;
struct sym *sp;
static short ramsrc[] =
{NO, NO, 12, 8, NO, NO, NO, NO, NO, 0, NO, NO};
#define ACC_DOPE 0
#define IMM_DOPE 2
#define DEE_DOPE 3
static short dest[] =
{NO, NO, NO, 0, NO, NO, 4, 5, NO, 1, NO, NO};
COUNT_OPERANDS(3, 3, nop);
if (op->r == D) {
curnode->no_flag = True;
}
if (op->r == RAM) {
quad = 0;
b = op->v;
CHKRNG(b);
switch ((op + 1)->r) {
case ACC:
a = ACC_DOPE + ramsrc[(op + 2)->r];
break;
case IMM:
case Z:
case SYM:
a = IMM_DOPE + ramsrc[(op + 2)->r];
break;
default:
goto botch;
}
if ((op + 2)->r == RAM && (op + 2)->v != b) {
c = (op + 2)->v;
if ((b & 0x10) != (c & 0x10)) {
error("r[%d] and r[%d] not in same half of ram", b, c);
}
if ((op + 1)->r == IMM || (op + 1)->r == Z || (op + 1)->r == SYM) {
error("two-register form illegal with immediate");
}
curnode->dreg_opd = True;
}
} else if ((op + 1)->r == RAM) {
quad = 0;
b = (op + 1)->v;
CHKRNG(b);
switch (op->r) {
case D:
a = DEE_DOPE + ramsrc[(op + 2)->r];
break;
default:
goto botch;
}
if ((op + 2)->r == RAM && (op + 2)->v != b) {
c = (op + 2)->v;
if ((b & 0x10) != (c & 0x10)) {
error("r[%d] and r[%d] not in same half of ram", b, c);
}
curnode->dreg_opd = True;
}
} else if ((op + 2)->r == RAM) {
quad = 2;
b = (op + 2)->v;
CHKRNG(b);
switch (op->r) {
case D:
switch ((op + 1)->r) {
case ACC:
a = 1;
break;
case IMM:
case Z:
case SYM:
a = 5;
break;
default:
goto botch;
}
break;
case ACC:
switch ((op + 1)->r) {
case IMM:
case Z:
case SYM:
a = 2;
break;
default:
goto botch;
}
break;
}
} else {
quad = 3;
switch (op->r) {
case D:
switch ((op + 1)->r) {
case ACC:
a = 1;
break;
case IMM:
case Z:
case SYM:
a = 5;
break;
default:
goto botch;
}
break;
case ACC:
switch ((op + 1)->r) {
case IMM:
case Z:
case SYM:
a = 2;
break;
default:
goto botch;
}
break;
default:
goto botch;
}
b = dest[(op + 2)->r];
}
/* assemble the instruction */
if (a < 0 || b < 0)
goto botch;
bits = (rp->value1 << 15) | (rp->value2 << 5);
bits |= (quad << 13) | (a << 9) | b;
curnode->word2 |= bits >> 8;
curnode->word3 |= bits << 8;
if (curnode->dreg_opd) {
curnode->word2 |= (c & 0xf) << 8;
curnode->word1 &= 0xf7ff;
}
if ((op + 1)->r == IMM || (op + 1)->r == Z) {
(curnode + 1)->word2 |= ((op + 1)->v >> 8) & 0xff;
(curnode + 1)->word3 |= (op + 1)->v << 8;
(curnode + 1)->imm_29116 = True;
} else if ((op + 1)->r == SYM) {
if ((sp = lookup((op + 1)->v)) == 0) {
sp = enter((op + 1)->v);
}
(curnode + 1)->symptr = sp;
(curnode + 1)->imm_sym = True;
}
DEBUG("Tor: b/w=%d, quad=%d, op=%x, a=%x, b=%x\n", rp->value1, quad, rp->value2, a, b);
return;
botch:
error("incompatible operands");
# undef ACC_DOPE
# undef IMM_DOPE
# undef DEE_DOPE
}
shf(rp, nop, op)
register RESERVED *rp;
int nop;
register OPERAND *op;
{
/* single-bit shifts */
unsigned short bits;
int quad;
int a,
b,
c;
COUNT_OPERANDS(2, 2, nop);
if (op->r == D) {
curnode->no_flag = True;
}
if ((op + 1)->r == RAM) {
quad = 2;
b = (op + 1)->v;
CHKRNG(b);
switch (op->r) {
case RAM:
a = 6;
if (op->v != b) {
c = b;
b = op->v;
if ((b & 0x10) != (c & 0x10)) {
error("r[%d] and r[%d] not in same half of ram",
b, c);
}
curnode->dreg_opd = True;
}
break;
case D:
a = 7;
break;
default:
botch:
error("incompatible operands");
return;
}
} else {
quad = 3;
switch (op->r) {
case ACC:
a = 6;
break;
case D:
a = 7;
break;
default:
goto botch;
}
switch ((op + 1)->r) {
case Y:
b = 0;
break;
case ACC:
b = 1;
break;
default:
goto botch;
}
}
/* assemble the instruction */
bits = (rp->value1 << 15) | (rp->value2 << 5);
bits |= (quad << 13) | (a << 9) | b;
curnode->word2 |= bits >> 8;
curnode->word3 |= bits << 8;
if (curnode->dreg_opd) {
curnode->word2 |= (c & 0xf) << 8;
curnode->word1 &= 0xf7ff;
}
DEBUG("Shf: b/w=%d, quad=%d, op=%x, a=%x, b=%x\n", rp->value1, quad, rp->value2, a, b);
}
bor(rp, nop, op)
register RESERVED *rp;
int nop;
register OPERAND *op;
{
/* bit testing and clearing, and other weird stuff */
unsigned short bits;
int quad;
int a,
b,
c;
int o;
Boolean n_used = False;
COUNT_OPERANDS(2, 3, nop);
if ((op + 1)->r == D) {
curnode->no_flag = True;
}
/* first operand is bit number -- must be in range */
if (op->r == NREG) {
n_used = True;
a = 0;
} else if ((op->r != Z && op->r != IMM) || (a = op->v) < 0 || a > 15) {
error("bad bit index");
return;
}
if ((op + 1)->r == RAM) {
static short quads[] = {3, 3, 3, 2, 2, 2, 2};
static short oos[] = {13, 14, 15, 14, 15, 12, 13};
b = (op + 1)->v;
CHKRNG(b);
quad = quads[rp->value2];
o = oos[rp->value2];
if (nop == 3) {
if ((op + 2)->r == RAM) {
if (b == (op + 2)->v) {
c = 0;
} else {
c = (op + 2)->v;
curnode->dreg_opd = True;
if ((b & 0x10) != (c & 0x10)) {
error("r[%d] and r[%d] not in same half of ram", b, c);
}
}
} else {
goto botch;
}
}
} else {
static short acc[] = {2, 1, 0, 4, 5, 6, 7};
static short dee[] = {18, 17, 16, 20, 21, NO, NO};
static short yew[] = {NO, NO, NO, NO, NO, 22, 23};
if ((rp->value2 == 0 || rp->value2 == 1 ||
rp->value2 == 3 || rp->value2 == 4) && (op + 1)->r == D) {
if (nop != 3 || (op + 2)->r != Y) {
goto botch;
}
} else if (nop == 3) {
goto botch;
}
o = 12;
quad = 3;
switch ((op + 1)->r) {
case ACC:
b = acc[rp->value2];
break;
case D:
b = dee[rp->value2];
break;
case Y:
b = yew[rp->value2];
break;
default:
botch:
error("incompatible operands");
return;
}
if (b < 0)
goto botch;
}
/* assemble the instruction */
bits = (rp->value1 << 15) | (quad << 13);
bits |= (a << 9) | (o << 5) | b;
curnode->word2 |= bits >> 8;
curnode->word3 |= bits << 8;
if (n_used) {
curnode->word1 |= 0x1000;
}
if (curnode->dreg_opd) {
curnode->word2 |= (c & 0xf) << 8;
curnode->word1 &= 0xf7ff;
}
DEBUG("Bor: b/w=%d, quad=%d, op=%x, a=%x, b=%x\n", rp->value1, quad, o, a, b);
}
rot(rp, nop, op)
register RESERVED *rp;
int nop;
register OPERAND *op;
{
/* rotate by n bits */
unsigned short bits;
int quad;
Boolean n_used = False;
int a,
b,
c;
int o;
static short ramsrc[] =
{NO, NO, 15, 14, NO, NO, NO, NO, NO, 12, NO, NO};
static short ramsrc2[] =
{NO, 1, NO, NO, NO, NO, NO, NO, NO, 0, NO, NO};
static short xsrc[] =
{NO, NO, NO, 24, NO, NO, NO, NO, NO, 25, NO, NO};
# define DEE_DOPE 0
# define ACC_DOPE 4
COUNT_OPERANDS(3, 3, nop);
if ((op + 1)->r == D) {
curnode->no_flag = True;
}
/* first operand is bit number -- must be in range */
if (op->r == NREG) {
n_used = True;
a = 0;
} else if ((op->r != Z && op->r != IMM && op->r != SYM)
|| (a = op->v) < 0 || a > 15) {
error("bad bit index");
return;
}
if ((op + 1)->r == RAM) {
quad = 0;
b = (op + 1)->v;
CHKRNG(b);
o = ramsrc[(op + 2)->r];
if ((op + 2)->r == RAM && (op + 2)->v != b) {
c = (op + 2)->v;
if ((b & 0x10) != (c & 0x10)) {
error("r[%d] and r[%d] not in same half of ram", b, c);
}
curnode->dreg_opd = True;
}
} else if ((op + 2)->r == RAM) {
quad = 1;
b = (op + 2)->v;
CHKRNG(b);
o = ramsrc2[(op + 1)->r];
} else {
quad = 3;
o = 12;
switch ((op + 1)->r) {
case D:
b = DEE_DOPE + xsrc[(op + 2)->r];
break;
case ACC:
b = ACC_DOPE + xsrc[(op + 2)->r];
break;
default:
goto botch;
}
}
/* assemble the instruction */
if (b < 0 || o < 0)
goto botch;
bits = (rp->value1 << 15) | (quad << 13);
bits |= (a << 9) | (o << 5) | b;
curnode->word2 |= bits >> 8;
curnode->word3 |= bits << 8;
if (n_used) {
curnode->word1 |= 0x1000;
}
if (curnode->dreg_opd) {
curnode->word2 |= (c & 0xf) << 8;
curnode->word1 &= 0xf7ff;
}
DEBUG("Rot: b/w=%d, quad=%d, op=%x, a=%x, b=%x\n", rp->value1, quad, o, a, b);
return;
botch:
error("incompatible operands");
# undef ACC_DOPE
# undef DEE_DOPE
}
rom(rp, nop, op)
register RESERVED *rp;
int nop;
register OPERAND *op;
{
/* rotate and xxxxx instructions */
/* operands are: shift count; shifted source; mask; destination
* (comparand) */
unsigned short bits;
int quad = 1;
int a,
b;
int o;
struct sym *sp;
Boolean n_used = False;
register struct dee {
short accdst[12];
short ramdst[12];
short accram,
ramacc;
} *d;
static struct dee darray[2] = {
{ /* for rotate-and-merge */
{NO, NO, 8, NO, NO, NO, NO, NO, 7, NO, NO, 7},
{NO, NO, NO, NO, NO, NO, NO, NO, 9, 10, NO, 9},
12, 14,
},
{ /* for rotate-and-compare */
{NO, NO, NO, NO, NO, NO, NO, NO, 2, NO, NO, 2},
{NO, NO, NO, NO, NO, NO, NO, NO, 3, 4, NO, 3},
NO, 5,
},
};
COUNT_OPERANDS(4, 4, nop);
/* first operand is bit number -- must be in range */
if (op->r == NREG) {
n_used = True;
a = 0;
} else if ((op->r != Z && op->r != IMM) || (a = op->v) < 0 || a > 15) {
error("bad bit index");
}
if ((op + 1)->r == D) {
curnode->no_flag = True;
}
b = 0;
d = &darray[rp->value2];
if ((op + 1)->r == D) {
switch ((op + 2)->r) {
case ACC:
o = d->accdst[(op + 3)->r];
if ((op + 3)->r == RAM) {
b = (op + 3)->v;
}
break;
case RAM:
o = d->ramdst[(op + 3)->r];
b = (op + 2)->v;
break;
default:
goto botch;
}
} else if ((op + 1)->r == ACC && ((op + 3)->r == IMM || (op + 3)->r == Z
|| (op + 3)->r == SYM)
&& (op + 2)->r == RAM) {
o = d->accram;
b = (op + 2)->v;
} else if ((op + 1)->r == RAM && ((op + 3)->r == IMM || (op + 3)->r == Z
|| (op + 3)->r == SYM)
&& (op + 2)->r == ACC) {
o = d->ramacc;
b = (op + 1)->v;
} else {
botch:
error("incompatible operands");
return;
}
if ((op + 3)->r == IMM || (op + 3)->r == Z) {
(curnode + 1)->word2 |= ((op + 3)->v >> 8) & 0xff;
(curnode + 1)->word3 |= (op + 3)->v << 8;
(curnode + 1)->imm_29116 = True;
} else if ((op + 3)->r == SYM) {
if ((sp = lookup((op + 3)->v)) == 0) {
sp = enter((op + 3)->v);
}
(curnode + 1)->symptr = sp;
(curnode + 1)->imm_sym = True;
}
/* assemble the instruction */
CHKRNG(b);
if (o < 0)
goto botch;
bits = (rp->value1 << 15) | (quad << 13);
bits |= (a << 9) | (o << 5) | b;
curnode->word2 |= bits >> 8;
curnode->word3 |= bits << 8;
if (n_used) {
curnode->word1 |= 0x1000;
}
DEBUG("Rom: b/w=%d, quad=%d, op=%x, a=%x, b=%x\n", rp->value1, quad, o, a, b);
}
etc(rp, nop, op)
register RESERVED *rp;
int nop;
register OPERAND *op;
{
/* random, unrelated instructions */
unsigned short bits;
int quad;
struct sym *sp;
int a,
b,
c;
int o;
Boolean hasopd1;
static short nnops[] = {3, 1, 1, 1, 0};
static short pmasks[] = {10, NO, NO, NO, NO, NO, NO, NO, 11, 8, NO, 11};
static short pdest1[] = {NO, NO, NO, 2, NO, NO, NO, NO, NO, 0, NO, NO};
static short pdest2[] = {NO, NO, 11, 10, NO, NO, NO, NO, NO, 8, NO, NO};
static short pdest4[] = {NO, NO, NO, 0, NO, NO, NO, NO, NO, 1, NO, NO};
static short psrc2[] = {NO, 9, NO, NO, NO, NO, NO, NO, NO, 7, NO, NO};
static short psrc3[] = {NO, 6, 3, NO, NO, NO, NO, NO, NO, 4, NO, NO};
static short psrc4[] = {NO, 6, NO, NO, NO, NO, NO, NO, NO, 4, NO, NO};
static short stdst1[] = {3, 5, 6, 9, 10};
static short stdst2[] = {NO, NO, NO, 0, NO, NO, NO, NO, NO, 1, NO, NO};
hasopd1 = False;
COUNT_OPERANDS(nnops[rp->value2], nnops[rp->value2], nop);
if (op != 0 && nnops[rp->value2] >= 1 && op->r == D) {
curnode->no_flag = True;
}
switch (rp->value2) {
case 0: /* prioritize instruction */
/* three operands: source, mask, destination */
hasopd1 = True;
if (op->r == RAM) {
/* case 1: RAM source */
if ((op + 2)->r == RAM)
goto case3; /* cases hard to tell apart */
quad = 2;
o = pdest1[(op + 2)->r];
a = pmasks[(op + 1)->r];
b = op->v;
CHKRNG(b);
} else if ((op + 1)->r == RAM) {
/* case 2: RAM mask */
quad = 2;
o = psrc2[op->r];
a = pdest2[(op + 2)->r];
b = (op + 1)->v;
CHKRNG(b);
} else if ((op + 2)->r == RAM) {
case3: /* case 3: RAM destination */
quad = 2;
o = psrc3[op->r];
a = pmasks[(op + 1)->r];
b = (op + 2)->v;
CHKRNG(b);
if (op->r == RAM && op->v != b) {
c = b;
b = op->v;
if ((b & 0x10) != (c & 0x10)) {
error("r[%d] and r[%d] not in same half of ram",
b, c);
}
if ((op + 1)->r == RAM) {
error("two-register form illegal with immediate");
}
curnode->dreg_opd = True;
}
} else {
/* case 4: no RAM involved in transaction */
quad = 3;
o = psrc4[op->r];
a = pmasks[(op + 1)->r];
b = pdest4[(op + 2)->r];
}
if ((op + 1)->r == Z && (op + 1)->v != 0)
goto botch;
/* assemble it */
if (a < 0 || b < 0 || o < 0)
goto botch;
bits = (rp->value1 << 15) | (quad << 13);
bits |= (a << 9) | (o << 5) | b;
DEBUG("Prioritize: b/w=%d, quad=%d, op=%x, a=%x, b=%x\n", rp->value1, quad, o, a, b);
break;
case 1: /* crc instructions */
if (op->r != RAM)
goto botch;
b = op->v;
CHKRNG(b);
if (rp->value1)
o = 9;
else
o = 3;
bits = (6 << 13) + (6 << 9) + (o << 5) + b;
DEBUG("Crc: o=%x, b=%x\n", o, b);
break;
case 2: /* status register instructions */
curnode->word2 |= (rp->value1 == 0) ? 0x77 : 0x75;
curnode->word3 |= 0x4000;
curnode->word3 |= stdst1[op->r] << 8;
break;
case 3: /* status register saving
* instructions */
if (op->r == RAM) {
if (rp->value1 == 0)
goto rbotch;
bits = 0xcf40 | (op->v & 0xf);
} else {
bits = ((rp->value1 == 0) ? 0x6f40 : 0xef40) |
(stdst2[op->r] & 0xf);
}
break;
case 4: /* noop instruction */
bits = 0x7140;
DEBUG("Nop\n");
break;
default:
fatal("etc subop out of range");
}
curnode->word2 |= bits >> 8;
curnode->word3 |= bits << 8;
if (curnode->dreg_opd) {
curnode->word2 |= (c & 0xf) << 8;
curnode->word1 &= 0xf7ff;
}
if (hasopd1 && (op + 1)->r == IMM) {
(curnode + 1)->word2 |= ((op + 1)->v >> 8) & 0xff;
(curnode + 1)->word3 |= (op + 1)->v << 8;
(curnode + 1)->imm_29116 = True;
} else if (hasopd1 && (op + 1)->r == SYM) {
if ((sp = lookup((op + 1)->v)) == 0) {
sp = enter((op + 1)->v);
}
(curnode + 1)->symptr = sp;
(curnode + 1)->imm_sym = True;
}
return;
botch:
error("incompatible operands");
return;
rbotch:
error("movsw required for ram destination");
}
#ifdef VIEW
Boolean
asrcdest(src, dest, gentype, num, name)
int src,
dest;
SYMTYPE gentype;
int num;
char *name;
{
int sd;
struct sym *sp;
curnode->filled = True;
if (curnode->no_flag && src == FL2REG && dest == AM) {
warn("instr. moves fl2reg to am29116 & has D reg. as an am29116 operand");
}
if (src == -1 && dest == -1) {
curnode->word1 |= SRCDST_DEFAULT << 4;
} else {
if ((sd = srcdesttab[src][dest]) == -1) {
error("illegal source/destination combination");
return False;
} else {
if (src == GENERAL) {
curnode->has_genl = True;
if (gentype == NUMBER) {
curnode->word3 |= (num >> 8) & 0xff;
curnode->word4 |= num << 8;
curnode->genl_sym = False;
} else {
if ((sp = lookup(name)) == 0) {
sp = enter(name);
}
curnode->symptr = sp;
curnode->genl_sym = True;
}
}
curnode->word1 |= sd << 4;
if (dest == FPREGH || dest == FPREGL) {
(curnode + 1)->no_fpstore = True;
}
if (dest == SHMEM) {
(curnode + 1)->no_shmread = True;
}
if ((src == SHMEM) && curnode->no_shmread) {
warn("shared memory write followed by shared memory read");
}
if (dest == VPPROMP) {
(curnode + 1)->no_promread = True;
(curnode + 2)->no_promread = True;
}
if ((src == VPPROM) && curnode->no_promread) {
warn("write to prom pointer followed by read from prom");
}
if (curnode->no_shminc && dest == SHMEM) {
curnode->no_shminc = False;
}
if (curnode->no_fpinc && (dest == FPREGH || dest == FPREGL)) {
curnode->no_fpinc = False;
}
}
}
if (curnode->fphilo != NOTFP) {
if ((curnode->fphilo == HIGH && (src == FPREGL || dest == FPREGL))
|| (curnode->fphilo == LOW && (src == FPREGH || dest == FPREGH))) {
error("inconsistent setting of hi/lo bit");
return False;
}
}
if (src == FPREGH || dest == FPREGH) {
curnode->fphilo = HIGH;
} else if (src == FPREGL || dest == FPREGL) {
curnode->fphilo = LOW;
curnode->word1 |= 0x400;
}
return True;
}
#endif
#ifdef PAINT
Boolean
asrcdest(src, dest, gentype, num, name)
int src,
dest;
SYMTYPE gentype;
int num;
char *name;
{
int sd;
struct sym *sp;
curnode->filled = True;
if (curnode->no_flag && src == FL2REG && dest == AM) {
warn("instr. moves fl2reg to am29116 & has D reg. as an am29116 operand");
}
if (src == -1 && dest == -1) {
curnode->word1 |= SRCDST_DEFAULT << 4;
} else {
if ((sd = srcdesttab[dest][src]) == -1) {
error("illegal source/destination combination");
return False;
} else {
if (src == GENERAL) {
curnode->has_genl = True;
if (gentype == NUMBER) {
curnode->word3 |= (num >> 8) & 0xff;
curnode->word4 |= num << 8;
curnode->genl_sym = False;
} else {
if ((sp = lookup(name)) == 0) {
sp = enter(name);
}
curnode->symptr = sp;
curnode->genl_sym = True;
}
}
curnode->word1 |= sd << 4;
if (dest == SCRMEM) {
(curnode + 1)->no_scrmread = True;
}
if ((src == SCRMEM) && curnode->no_scrmread) {
warn("shared memory write followed by shared memory read at location %7x", curnode - 1);
}
if (dest == PPPROMP) {
(curnode + 1)->no_promread = True;
(curnode + 2)->no_promread = True;
}
if ((src == PPPROM) && curnode->no_promread) {
warn("write to prom pointer followed by read from prom at location %7x", curnode - 1);
}
if (curnode->no_scrminc && dest == SCRMEM) {
curnode->no_scrminc = False;
}
}
}
return True;
}
#endif
Boolean
aseq(rp, notflag, ccp, which, num, sym)
register RESERVED *rp;
Boolean notflag;
register RESERVED *ccp;
SYMTYPE which;
int num;
char *sym;
{
SYMBOL *sp;
curnode->filled = True;
if (rp == 0) {
curnode->word1 |= CONTINUE;
} else {
#ifdef VIEW
curnode->word1 |= (rp == 0) ? -1 : rp->value1;
curnode->word2 |=
(ccp == 0) ? 0 : (((int) notflag << 3) | ccp->value1) << 12;
if (curnode->fp_used) {
error("multiple use of variable field");
return False;
}
#endif
#ifdef PAINT
curnode->word1 |= rp->value1;
if (ccp != 0) {
if (ccp->value1 == -1) {
curnode->word1 |= 0x8000;
} else {
curnode->word2 |= (((int) notflag << 3)
| (ccp->value1 % 16)) << 12;
if (ccp->value1 >= 16) {
if (curnode->dreg_opd) {
error("three-way branch not allowed with two-register Am29116 instruction");
return False;
}
curnode->three_way = True;
}
}
}
#endif
if (which == NUMBER) {
if (curnode->has_genl) {
if (curnode->genl_sym
|| (curnode->word3 & 0xff) != ((num >> 8) & 0xff)
|| (curnode->word4 & 0xff00) != ((num << 8))) {
error("multiple use of variable field");
return False;
}
} else {
curnode->has_genl = True;
curnode->genl_sym = False;
curnode->word3 |= (num >> 8) & 0xff;
curnode->word4 |= num << 8;
}
} else if (which == ALPHA) {
if ((sp = lookup(sym)) == 0) {
sp = enter(sym);
}
if (curnode->has_genl) {
if (!curnode->genl_sym
|| (curnode->symptr != sp)) {
error("multiple use of variable field");
return False;
}
} else {
curnode->has_genl = True;
curnode->genl_sym = True;
curnode->symptr = sp;
}
} else {
curnode->word1 |= 0x4000;
}
#ifdef PAINT
if (curnode->three_way && !curnode->has_genl) {
error("three-way branch requires label in 2910 inst.");
return False;
}
#endif
}
return True;
}
#ifdef VIEW
Boolean
almode(round, inf, mode, code)
int round,
inf,
mode,
code;
{
if (curnode->has_genl) {
error("line has both general field value and floating point");
return False;
} else if (curnode->fphilo != NOTFP) {
if ((curnode->fphilo == HIGH && mode == 1)
|| (curnode->fphilo == LOW && mode == 0)) {
error("hi/lo bit inconsistent with mode operand in lmode");
return False;
}
}
curnode->filled = True;
curnode->word4 |= (round << 14) | 0x3000;
curnode->word3 |= inf;
curnode->word3 |= code << 1;
curnode->word1 |= mode << 10;
curnode->word1 |= 0x8000;
return True;
}
Boolean
aflt(rp, load, unld, store, select)
register RESERVED *rp;
int load,
unld,
store,
select;
{
curnode->filled = True;
if (rp != 0) {
if (curnode->has_genl) {
error("general field value and floating-point");
return False;
}
if (curnode->fphilo != NOTFP) {
if ((curnode->fphilo == HIGH && select == 1)
|| (curnode->fphilo == LOW && select == 0)) {
error("inconsistent setting of hi/lo bit");
return False;
}
}
(curnode + 1)->fphilo = (select == 0) ? LOW : HIGH;
curnode->fp_used = True;
curnode->word3 |= rp->value1 >> 2;
curnode->word4 |= rp->value1 << 14;
curnode->word4 |= rp->value2 << 11;
curnode->word4 |= load << 12;
curnode->word4 |= unld << 9;
curnode->word4 |= store << 8;
curnode->word1 |= select << 10;
(curnode + 1)->word1 |= (!select) << 10;
curnode->word1 |= 0x8000;
(curnode + 1)->word1 |= 0x8000;
/* bus move to fpregh or fpregl followed by flpt with store */
if (curnode->no_fpstore && (curnode->word1 & 0x8000)
&& (curnode->word4 & 0x100)) {
warn("move to fpregh or fpregl followed by floating point store");
}
}
if ((curnode - 1)->fp_used) {
if (curnode->fp_used) {
error("floating-point instructions in two consecutive lines");
return False;
} else {
if (curnode->has_genl) {
error("fl. pt. line followed by general field line");
return False;
} else {
curnode->word1 |= 0x8000;
curnode->word3 |= (curnode - 1)->word3 & 0xff;
curnode->word4 |= (curnode - 1)->word4 & 0xff00;
}
}
}
return True;
}
#endif
#ifdef VIEW
Boolean
acontrol(ctrl, op, ctrl2)
int ctrl,
op,
ctrl2;
{
curnode->filled = True;
if (ctrl == -1) {
return False;
} else {
if ((curnode->word1 & 0x800) == 0) {
error("two-register 29116 instruction and control field");
return False;
} else {
if (ctrl == 1) {
if (ctrl2 == -1) {
curnode->word2 |= (ctrl + op) << 8;
} else {
curnode->word2 |= (8 + (op << 1) + ctrl2) << 8;
}
} else {
curnode->word2 |= ctrl << 8;
}
}
if ((curnode + 1)->no_shmread && (ctrl == 0) && (op != 0)) {
(curnode + 1)->no_shminc = True;
}
if (curnode->no_shminc && (ctrl == 0) && (op != 0)) {
warn("write to shared mem. with inc. or dec. followed by non-write to shared mem. with inc. or dec.");
}
if ((curnode + 1)->no_fpstore && (ctrl != 0)) {
(curnode + 1)->no_fpinc = True;
}
if (curnode->no_fpinc && (ctrl == 0)) {
warn("write to floating reg. with inc. followed by non-write to floating reg. with inc.");
}
}
return True;
}
#endif
#ifdef PAINT
Boolean
acontrol(ctrl)
int ctrl;
{
curnode->filled = True;
if (ctrl == -1) {
if (curnode->three_way) {
error("three-way branch requires vmerd or vmewr control field");
return False;
}
return True;
} else {
if ((curnode->word1 & 0x800) == 0) {
error("two-register 29116 instruction and control field");
} else {
if (curnode->three_way) {
if (ctrl >= 6) {
curnode->word2 |= (ctrl + 8) << 8;
curnode->word1 |= 0x4000;
} else {
error("three-way branch requires vmerd or vmewr control field");
return False;
}
} else {
curnode->word2 |= ctrl << 8;
}
}
if ((curnode + 1)->no_scrmread && (ctrl == 0)) {
(curnode + 1)->no_scrminc = True;
}
if (curnode->no_scrminc && (ctrl == 0)) {
warn("write to shared mem. with inc. or dec. followed by non-write to shared mem. with inc. or dec. at location %7x", curnode - 1);
}
}
return True;
}
#endif
void
asccs(cp)
char *cp;
{
--cp;
while (True) {
curnode->filled = True;
curnode->sccsid = True;
curnode->addr = curaddr;
curnode->word1 = 0;
curnode->word2 = 0;
curnode->word3 = 0;
curnode->word4 = 0;
if (*(++cp) == '\n') {
curnode->word1 = '\0' << 8;
break;
} else {
curnode->word1 = *cp << 8;
}
if (*cp == '\0')
break;
if (*(++cp) == '\n') {
curnode->word1 |= '\0';
break;
} else {
curnode->word1 |= *cp & 0xff;
}
if (*cp == '\0')
break;
if (*(++cp) == '\n') {
curnode->word2 = '\0' << 8;
break;
} else {
curnode->word2 = *cp << 8;
}
if (*cp == '\0')
break;
if (*(++cp) == '\n') {
curnode->word2 |= '\0';
break;
} else {
curnode->word2 |= *cp & 0xff;
}
if (*cp == '\0')
break;
if (*(++cp) == '\n') {
curnode->word3 = '\0' << 8;
break;
} else {
curnode->word3 = *cp << 8;
}
if (*cp == '\0')
break;
if (*(++cp) == '\n') {
curnode->word3 |= '\0';
break;
} else {
curnode->word3 |= *cp & 0xff;
}
if (*cp == '\0')
break;
if (*(++cp) == '\n') {
curnode->word4 = '\0' << 8;
break;
} else {
curnode->word4 = *cp << 8;
}
if (*cp == '\0')
break;
curlineno++;
anext();
curnode->line = NULL;
curaddr++;
}
}
resolve_addrs()
{
NODE *nd;
struct sym *sp;
for (nd = n; nd <= curnode; nd++) {
if (nd->has_genl && nd->genl_sym) {
sp = nd->symptr;
if (sp->defined) {
nd->word3 |= ((sp->node->addr) >> 8) & 0xff;
nd->word4 |= (sp->node->addr) << 8;
}
} else if (nd->imm_sym) {
sp = nd->symptr;
if (sp->defined) {
nd->word2 &= 0xff00;
nd->word2 |= ((sp->node->addr) >> 8) & 0xff;
nd->word3 &= 0xff;
nd->word3 |= (sp->node->addr) << 8;
}
}
}
}