BSD 4 release
[unix-history] / usr / src / cmd / as / ascode.c
index cd33244..1cf20f5 100644 (file)
-/* Copyright (c) 1979 Regents of the University of California */
+/* Copyright (c) 1980 Regents of the University of California */
+static char sccsid[] = "@(#)ascode.c 4.7 11/5/80";
 #include <stdio.h>
 #include "as.h"
 #include "assyms.h"
 
 #include <stdio.h>
 #include "as.h"
 #include "assyms.h"
 
+/*
+ *     Loader reference types  (plust PCREL) to bytes and lg bytes
+ */
+/*             LEN1    LEN1+PC LEN2    LEN2+PC LEN4    LEN4+PC LEN8    LEN8+PC*/
+int    reflen[] =      /* {LEN*+PCREL} ==> number of bytes */
+{0,    0,      1,      1,      2,      2,      4,      4,      8,      8};     
+int    lgreflen[] =    /* {LEN*+PCREL} ==> lg number of bytes */ 
+{-1,   -1,     0,      0,      1,      1,      2,      2,      3,      3};
+
+/*
+ *     Sizes to Loader reference types and type flags
+ */
+/*0    1       2       3       4       5       6       7       8*/
+int    len124[] =      /* {1,2,4,8} ==> {LEN1, LEN2, LEN4, LEN8} */
+{0,    LEN1,   LEN2,   0,      LEN4,   0,      0,      0,      LEN8};
+char   mod124[] =      /* {1,2,4,8} ==> {bits to construct operands */
+{0,    0x00,   0x20,   0,      0x40,   0,      0,      0,      0};
+int    type_124[] =    /* {1,2,4,8} ==> {TYPB, TYPW, TYPL, TYPQ} */
+{0,     TYPB,  TYPW,    0,      TYPL,   0,      0,      0,      TYPQ};
+
+/*
+ *     type flags to Loader reference and byte lengths
+ */
+/*TYPB TYPW    TYPL    TYPQ    TYPF    TYPD*/
+int    ty_NORELOC[] =  /* {TYPB..TYPD} ==> {1 if relocation not OK */
+{0,    0,      0,      1,      1,      1};
+int    ty_LEN[] =      /* {TYPB..TYPD} ==> {LEN1..LEN8} */
+{LEN1, LEN2,   LEN4,   LEN8,   LEN4,   LEN8};
+int    ty_nbyte[] =    /* {TYPB..TYPD} ==> {1,2,4,8} */
+{1,    2,      4,      8,      4,      8};
+int    ty_nlg[] =      /* {TYPB..TYPD} ==> lg{1,2,4,8} */
+{0,    1,      2,      3,      2,      3};
+
 insout(op, ap, nact)
        struct arg *ap;
 {
 insout(op, ap, nact)
        struct arg *ap;
 {
-       int jxxflg;
-
+       int             jxxflg;
+       register        struct  instab  *ip;            /* the instruction */
+       register        struct  arg     *ap_walk;       /* actual param walk */
+       register        int     i;
+       register        int     ap_type;                /* actual param type */
+       register        int     ap_type_mask;           /* masked actual param */
        op &= 0xFF;
        jxxflg = nact;
        if (nact < 0)
                nact = -nact;
        op &= 0xFF;
        jxxflg = nact;
        if (nact < 0)
                nact = -nact;
-       if (passno!=2) {
-               register struct arg     *ap2;
-               register struct instab  *ip;
-               int                     i,nexp;
-               ip = itab[op];
-               nexp = ip->nargs;
-               if (nact < nexp)
-                       yyerror("Too few arguments");
-               if (nact > nexp) {
-                       yyerror("Too many arguments");
-                       nact = nexp;
-               }
+       if (passno == 1) {
+           ip = itab[op];
+           if (nact < ip->i_nargs)
+               yyerror("Too few arguments");
+           if (nact > ip->i_nargs) {
+               yyerror("Too many arguments");
+               nact = ip->i_nargs;
+           }
+           /*
+            *  Check argument compatability with instruction template
+            */
+           for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){
+               ap_type = ap_walk->a_atype;
+               ap_type_mask = ap_type & AMASK;
                /*
                /*
-                *      Check argument compatability with instruction template
+                *      The switch value is >> by 3 so that the switch
+                *      code is dense, not implemented as a sequence
+                *      of branches but implemented as a casel.
+                *      In addition, cases ACCI and ACCR are added to force
+                *      dense switch code.
                 */
                 */
-               for (ap2 = ap+nact, i = nact; --i >= 0;)
-                       argcompat(--ap2, ip->argtype[i], i);
-       }
+               switch( ((fetcharg(ip, i-1)) & ACCESSMASK)>>3){ /* type of fp */
+               case ACCI >> 3:
+               case ACCR >> 3:
+                       break;
+               case ACCB >> 3:
+                       if ( !((ap_type_mask == AEXP) || (ap_type_mask == AIMM)) ){
+                               yyerror("arg %d, branch displacement must be an expression",i);
+                               return;
+                       }
+                       break;
+               case ACCA >> 3:
+                       switch(ap_type_mask){
+                       case AREG:      yyerror("arg %d, addressing a register",i);
+                                       return;
+                       case AIMM:      if ( !(ap_type & ASTAR) ){
+                                        yyerror("arg %d, addressing an immediate operand",i);
+                                        return;
+                                       }
+                       }
+                       break;
+               case ACCM >> 3:
+               case ACCW >> 3:
+                       switch(ap_type_mask){
+                       case AIMM:      if (!(ap_type&ASTAR)) {
+                                        yyerror("arg %d, modifying a constant",i);
+                                        return;
+                                       }
+                       }
+                       break;
+               }       /* end of the switch on fp_type */
+               if (ap_type & AINDX) {
+                       if (ap_walk->a_areg2==0xF) {
+                               yyerror("arg %d, PC used as index",i);
+                               return;
+                       }
+                       switch(ap_type_mask){
+                       case AREG:      yyerror("arg %d, indexing the register file",i);
+                                       return;
+                       case AIMM:      yyerror("arg %d, indexing a constant",i);
+                                       return;
+                       case ADECR:
+                       case AINCR:     if (ap_walk->a_areg1==ap_walk->a_areg2) {
+                                               yyerror("arg %d, indexing with modified register",i);
+                                               return;
+                                       }
+                                       break;
+                       }       /* end of switch on ap_type_mask */
+               } /* end of AINDX */
+          }
+       } /* both passes here */
        if (jxxflg < 0)
                ijxout(op, ap, nact);
        else putins(op, ap, nact);
 }
 
        if (jxxflg < 0)
                ijxout(op, ap, nact);
        else putins(op, ap, nact);
 }
 
-argcompat(act, exp, i)
-       struct arg *act;
-       int exp,i;
-{
-       register        at,atm;
-
-       at = act->atype;
-       atm = at & AMASK;
-
-       if ((exp & ACCA) && (atm == AREG)) {
-               yyerror("arg %d, addressing a register",i);
-               return;
-       }
-       if ((exp&ACCW) && (atm==AIMM) && !(at&ASTAR)) {
-               yyerror("arg %d, modifying a constant",i);
-               return;
-       }
-       if (at & AINDX) {
-               if (act->areg2==017) {
-                       yyerror("arg %d, PC used as index",i);
-                       return;
-               }
-               if (atm==AREG) {
-                       yyerror("arg %d, indexing the register file",i);
-                       return;
-               }
-               if (atm==AIMM) {
-                       yyerror("arg %d, indexing a constant",i);
-                       return;
-               }
-               if (((atm==ADECR) || (atm==AINCR)) && (act->areg1==act->areg2)) {
-                       yyerror("arg %d, indexing with modified register",i);
-                       return;
-               }
-       }
-}
-
-int d124 =     {4};
-int len124[] =         {0,LEN1,LEN2,0,LEN4};
-char mod124[] = {0,0x00,0x20,0,0x40};
+extern int d124;
 
 putins(op, ap, n)
        /*
 
 putins(op, ap, n)
        /*
@@ -83,192 +135,241 @@ putins(op, ap, n)
        register struct arg *ap;
 {
        register struct exp     *xp;
        register struct arg *ap;
 {
        register struct exp     *xp;
-       register int            a;
-       int                     i,xtrab;
+       register int            argtype;
+       int                     i;
+       int                     reloc_how;
 
 
-       if (passno!=2) {
-               dotp->xvalue += n+1;    /* 1 for the opcode, at least 1 per arg */
-               for (i=0; i<n; i++,ap++) {/* some args take more than 1 byte */
-                       a=ap->atype;
-                       if (a & AINDX)
-                               dotp->xvalue++;
-                       switch (a&~(AINDX|ASTAR)) {
-                               case AEXP: {
-                                       a = itab[op]->argtype[i];
-                                       if (a == ACCB+TYPB)
-                                               break;
-                                       if (a==ACCB+TYPW){
-                                               dotp->xvalue++;
-                                               break;
-                                       }
-                                       dotp->xvalue += ap->dispsize;
-                                       break;
-                               }
-                               case ADISP: {
-                                       xp=ap->xp;
-                                       if ((xp->xtype&XTYPE)!=XABS || xp->xtype&XFORW){
-                                               dotp->xvalue += ap->dispsize;
-                                               break;
-                                       }
-                                       if (xp->xvalue==0 && !(a&ASTAR))
+#ifdef DEBUG
+       fflush(stdout);
+#endif
+       if (passno == 2)
+               goto PASS2;
+
+       dotp->e_xvalue += n+1;          /* 1 for the opcode, at least 1 per arg */
+       for (i=0; i<n; i++,ap++) {      /* some args take more than 1 byte */
+           argtype = ap->a_atype;
+           if (argtype & AINDX)
+               dotp->e_xvalue++;
+           /*
+            *  This switch has been fixed by enumerating the no action
+            *  alternatives (those that have 1 one byte of code)
+            *  so that a casel instruction is emitted.
+            */
+           switch (argtype&~(AINDX|ASTAR)) {
+               case AREG:
+               case ABASE:
+               case ADECR:
+               case AINCR:
+                       break;
+               case AEXP: 
+                       argtype = fetcharg(itab[op], i);
+                       if (argtype == ACCB+TYPB)
+                               break;
+                       if (argtype==ACCB+TYPW){
+                               dotp->e_xvalue++;
+                               break;
+                       }
+                       /*
+                        *      Reduces to PC relative
+                        */
+                       dotp->e_xvalue += ap->a_dispsize;
+                       break;
+               
+               case ADISP: 
+                       xp=ap->a_xp;
+                       if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
+                               dotp->e_xvalue += ap->a_dispsize;
+                               break;
+                       }
+                       if (xp->e_xvalue==0 && !(argtype&ASTAR))
+                               break;
+                       dotp->e_xvalue++;
+                       if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE))
+                               dotp->e_xvalue++;
+                       if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD))
+                               dotp->e_xvalue += 2;
+                       break;
+
+               case AIMM: 
+                       if (ap->a_atype&ASTAR) argtype=TYPL;
+                       else {
+                               argtype = fetcharg(itab[op], i);
+                               if (argtype&ACCA)
+                                       argtype = TYPL;
+                               else
+                                       argtype &= TYPMASK;
+                               xp = ap->a_xp;
+                               if (   ((xp->e_xtype&XTYPE)==XABS)
+                                   && (!(xp->e_xtype&XFORW))
+                                   && (xp->e_xvalue>=0)
+                                   && (xp->e_xvalue<=63) 
+                                   && (xp->e_yvalue == 0)
+                                   && (argtype != TYPD)
+                                   && (argtype != TYPF)
+                               )
                                                break;
                                                break;
-                                       dotp->xvalue++;
-                                       if ((xp->xvalue<MINBYTE) || (xp->xvalue>MAXBYTE))
-                                               dotp->xvalue++;
-                                       if ((xp->xvalue<MINWORD) || (xp->xvalue>MAXWORD))
-                                               dotp->xvalue += 2;
-                                       break;
+                       }
+                       switch (argtype) {
+                       case TYPD:
+                       case TYPF:
+                               if (   !(((xp->e_xtype&XTYPE)==XABS)
+                                   && (!(xp->e_xtype&XFORW))
+                                   && (slitflt(xp)))
+                               ){
+                               /* it is NOT short */
+                                       dotp->e_xvalue += ((argtype==TYPF)?
+                                               4 : 8);
                                }
                                }
-                               case AIMM: {
-                                       if (ap->atype&ASTAR) a=TYPL;
-                                       else {
-                                               xp = ap->xp;
-                                               if ((xp->xtype&XTYPE)==XABS && !(xp->xtype&XFORW)
-                                                       && xp->xvalue>=0 && xp->xvalue<=63) 
-                                                               break;
-                                               a = itab[op]->argtype[i];
-                                               if (a&ACCA)
-                                                       a = TYPL;
-                                               else
-                                                       a &= TYPMASK;
-                                       }
-                                       switch (a) {
-                                               case TYPD:
-                                               case TYPF:
-                                                       if (slitflt(xp))
-                                                               break;
-                                                       if (a==TYPF)
-                                                               dotp->xvalue -= 4;
-                                               case TYPQ: 
-                                                       dotp->xvalue += 4;
-                                               case TYPL:
-                                                       dotp->xvalue += 2;
-                                               case TYPW: 
-                                                       dotp->xvalue++;
-                                               case TYPB: 
-                                                       dotp->xvalue++;
-                                       }       /*end of the switch on a*/
-                               }       /*end of case AIMM*/
-                       }       /*end of the switch on the type*/
-               }       /*end of looping for all arguments*/
-               return;
-       }       /*end of it being time for pass 1*/
-       /*
-        *      PASS2 HERE
-        */
+                               break;
+                       case TYPQ: 
+                               dotp->e_xvalue += 8;break;
+                       case TYPL:
+                               dotp->e_xvalue += 4;break;
+                       case TYPW: 
+                               dotp->e_xvalue += 2;break;
+                       case TYPB: 
+                               dotp->e_xvalue += 1;break;
+                       }       /*end of the switch on argtype*/
+           }   /*end of the switch on the type*/
+       }       /*end of looping for all arguments*/
+       return;
+
+PASS2:
 
 
+#ifdef UNIX
        outb(op); /* the opcode */
        outb(op); /* the opcode */
+#endif UNIX
+#ifdef VMS
+       *vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)op;
+       dotp->e_xvalue += 1;
+#endif VMS
+
        for (i=0; i<n; i++,ap++) {/* now for the arguments */
        for (i=0; i<n; i++,ap++) {/* now for the arguments */
-               a=ap->atype;
-               xp=ap->xp;
-               xtrab=0;
-               if (a&AINDX) {
-                       { outb(0x40 | ap->areg2); }
-                       a &= ~AINDX;
+               argtype=ap->a_atype;
+               xp=ap->a_xp;
+               reloc_how = TYPNONE;
+               if (argtype&AINDX) {
+#ifdef UNIX
+                       { outb(0x40 | ap->a_areg2); }
+#endif UNIX
+#ifdef VMS
+                       { *vms_obj_ptr++ = -1;
+                         *vms_obj_ptr++ = (0x40 | ap->a_areg2);
+                         dotp->e_xvalue += 1; }
+#endif VMS
+                       argtype &= ~AINDX;
                }
                }
-               if (a&ASTAR) {
-                       ap->areg1 |= 0x10;
-                       a &= ~ASTAR;
+               if (argtype&ASTAR) {
+                       ap->a_areg1 |= 0x10;
+                       argtype &= ~ASTAR;
                }
                }
-               switch (a) {
-                       case AREG:              /* %r */
-                               ap->areg1 |= 0x50;
-                               break; 
-                       case ABASE:             /* (%r) */
-                               ap->areg1 |= 0x60;
-                               break; 
-                       case ADECR:             /* -(%r) */
-                               ap->areg1 |= 0x70;
-                               break; 
-                       case AINCR:             /* (%r) */
-                               ap->areg1 |= 0x80;
+               switch (argtype) {
+               case AREG:              /* %r */
+                       ap->a_areg1 |= 0x50;
+                       break; 
+               case ABASE:             /* (%r) */
+                       ap->a_areg1 |= 0x60;
+                       break; 
+               case ADECR:             /* -(%r) */
+                       ap->a_areg1 |= 0x70;
+                       break; 
+               case AINCR:             /* (%r)+ */
+                       ap->a_areg1 |= 0x80;
+                       break;
+               case AEXP: /* expr */
+                       argtype = fetcharg(itab[op], i);
+                       if (argtype == ACCB+TYPB) {
+                               ap->a_areg1 = argtype = 
+                                       xp->e_xvalue - (dotp->e_xvalue + 1);
+                               if (argtype<MINBYTE || argtype>MAXBYTE)
+                                       yyerror("Branch too far"); break;
+                       }
+                       if (argtype == ACCB+TYPW) {
+                               ap->a_areg1 = argtype = xp->e_xvalue
+                                       -= dotp->e_xvalue + 2;
+                               xp->e_xtype = XABS;
+                               if (argtype<MINWORD || argtype>MAXWORD) 
+                                       yyerror("Branch too far");
+                               xp->e_xvalue = argtype>>8;
+                               reloc_how = TYPB;
                                break;
                                break;
-                       case AEXP: {/* expr */
-                               a = itab[op]->argtype[i];
-                               if (a == ACCB+TYPB) {
-                                       ap->areg1 = a = 
-                                               xp->xvalue - (dotp->xvalue + 1);
-                                       if (a<MINBYTE || a>MAXBYTE)
-                                               yyerror("Branch too far"); break;
-                               }
-                               if (a == ACCB+TYPW) {
-                                       ap->areg1 = a = xp->xvalue
-                                               -= dotp->xvalue + 2;
-                                       xp->xtype = XABS;
-                                       if (a<MINWORD || a>MAXWORD) 
-                                               yyerror("Branch too far");
-                                       xp->xvalue = a>>8;
-                                       xtrab = LEN1;
-                                       break;
-                               }
-                               /* reduces to expr(pc) mode */
-                               ap->areg1 |= (0xAF + mod124[ap->dispsize]);
-                               xtrab = len124[ap->dispsize]+PCREL;
+                       }
+                       /* reduces to expr(pc) mode */
+                       ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]);
+                       reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL;
+                       break;
+               
+               case ADISP: /* expr(%r) */
+                       ap->a_areg1 |= 0xA0;
+                       if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){
+                               ap->a_areg1 += mod124[ap->a_dispsize];
+                               reloc_how = type_124[ap->a_dispsize];
                                break;
                        }
                                break;
                        }
-                       case ADISP: {/* expr(%r) */
-                               ap->areg1 |= 0xA0;
-                               if ((xp->xtype&XTYPE)!=XABS || xp->xtype&XFORW){
-                                       ap->areg1 += mod124[ap->dispsize];
-                                       xtrab=len124[ap->dispsize];
-                                       break;
-                               }
-                               if (xp->xvalue==0 && !(ap->areg1&0x10)) {
-                                       ap->areg1 ^= 0xC0;
-                                       break;
-                               }
-                               xtrab=LEN1;
-                               if ((xp->xvalue<MINBYTE) || (xp->xvalue>MAXBYTE)){
-                                       ap->areg1 += 0x20;
-                                       xtrab=LEN2;
-                               }
-                               if ((xp->xvalue<MINWORD) || (xp->xvalue>MAXWORD)){
-                                       ap->areg1 += 0x20;
-                                       xtrab=LEN4;
-                               }
+                       if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) {
+                               ap->a_areg1 ^= 0xC0;
                                break;
                        }
                                break;
                        }
-                       case AIMM: { /* $expr */
-                               if (ap->atype&ASTAR)
-                                       a=TYPL;
-                               else {
-                                       if (    ( (xp->xtype&XTYPE) == XABS) 
-                                           && !(xp->xtype&XFORW)
-                                           &&  (xp->xvalue >= 0)
-                                           &&  (xp->xvalue <= 63) ) {
-                                               ap->areg1 = xp->xvalue;
-                                               break;
-                                       }
-                                       a = itab[op]->argtype[i];
-                                       if (a&ACCA)
-                                               a=TYPL;
-                                       else
-                                               a &= TYPMASK;
+                       reloc_how = TYPB;
+                       if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)){
+                               ap->a_areg1 += 0x20;
+                               reloc_how = TYPW;
+                       }
+                       if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)){
+                               ap->a_areg1 += 0x20;
+                               reloc_how = TYPL;
+                       }
+                       break;
+               
+               case AIMM:  /* $expr */
+                       if (ap->a_atype&ASTAR)
+                               argtype=TYPL;
+                       else {
+                               argtype = fetcharg(itab[op], i);
+                               if (argtype&ACCA)
+                                       argtype=TYPL;
+                               else
+                                       argtype &= TYPMASK;
+                               if (    ( (xp->e_xtype&XTYPE) == XABS) 
+                                   && !(xp->e_xtype&XFORW)
+                                   &&  (xp->e_xvalue >= 0)
+                                   &&  (xp->e_xvalue <= 63)
+                                   &&  (xp->e_yvalue == 0)
+                                   &&  (argtype != TYPF)
+                                   &&  (argtype != TYPD) ) {
+                                       ap->a_areg1 = xp->e_xvalue;
+                                       break;
                                }
                                }
-                               ap->areg1 |= 0x8F;
-                               switch (a) {
-                                       case TYPD:
-                                       case TYPF:
-                                               if (slitflt(xp)){
-                                                       ap->areg1=extlitflt(xp);
-                                                       break;
-                                               }
-                                               if (a==TYPF) { 
-                                                       xtrab = LEN4;
-                                                       break;
-                                               }
-                                       case TYPQ: xtrab = LEN8; break;
-                                       case TYPL: xtrab = LEN4; break;
-                                       case TYPW: xtrab = LEN2; break;
-                                       case TYPB: xtrab = LEN1; break;
+                       }
+                       ap->a_areg1 |= 0x8F;
+                       reloc_how = argtype;
+                       if (reloc_how == TYPD || reloc_how == TYPF){
+                               if (   ((xp->e_xtype&XTYPE)==XABS)
+                                   && (!(xp->e_xtype&XFORW))
+                                   && (slitflt(xp))
+                               ){
+                                       reloc_how = TYPNONE;
+                                       ap->a_areg1=extlitflt(xp);
                                }
                                }
-                       }       /*end of the switch on AIMM*/
-               }       /*end of the switch on a*/
+                       }       
+                       break;
+               
+               }       /*end of the switch on argtype*/
                /*
                 *      use the first byte to describe the argument
                 */
                /*
                 *      use the first byte to describe the argument
                 */
-               outb(ap->areg1);
-               if (xtrab) 
-                       outrel(&xp->xvalue, xtrab, xp->xtype, xp->xname);
+#ifdef UNIX
+               outb(ap->a_areg1);
+#endif UNIX
+#ifdef VMS
+               *vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)(ap->a_areg1);
+               dotp->e_xvalue += 1;
+               if ((vms_obj_ptr-sobuf) > 400) {
+                       write(objfil,sobuf,vms_obj_ptr-sobuf);
+                       vms_obj_ptr=sobuf+1;
+               }
+#endif VMS
+               if (reloc_how != TYPNONE) 
+                       outrel(xp, reloc_how);
        }       /*end of the for to pick up all arguments*/
 }
        }       /*end of the for to pick up all arguments*/
 }