1592Sbill /* Copyright (c) 1980 Regents of the University of California */ 2*1746Shenry static char sccsid[] = "@(#)ascode.c 4.7 11/05/80"; 3592Sbill #include <stdio.h> 4592Sbill #include "as.h" 5592Sbill #include "assyms.h" 6592Sbill 7673Shenry /* 8673Shenry * Loader reference types (plust PCREL) to bytes and lg bytes 9673Shenry */ 10673Shenry /* LEN1 LEN1+PC LEN2 LEN2+PC LEN4 LEN4+PC LEN8 LEN8+PC*/ 11673Shenry int reflen[] = /* {LEN*+PCREL} ==> number of bytes */ 12673Shenry {0, 0, 1, 1, 2, 2, 4, 4, 8, 8}; 13673Shenry int lgreflen[] = /* {LEN*+PCREL} ==> lg number of bytes */ 14673Shenry {-1, -1, 0, 0, 1, 1, 2, 2, 3, 3}; 15673Shenry 16673Shenry /* 17673Shenry * Sizes to Loader reference types and type flags 18673Shenry */ 19673Shenry /*0 1 2 3 4 5 6 7 8*/ 20673Shenry int len124[] = /* {1,2,4,8} ==> {LEN1, LEN2, LEN4, LEN8} */ 21673Shenry {0, LEN1, LEN2, 0, LEN4, 0, 0, 0, LEN8}; 22673Shenry char mod124[] = /* {1,2,4,8} ==> {bits to construct operands */ 23673Shenry {0, 0x00, 0x20, 0, 0x40, 0, 0, 0, 0}; 24673Shenry int type_124[] = /* {1,2,4,8} ==> {TYPB, TYPW, TYPL, TYPQ} */ 25673Shenry {0, TYPB, TYPW, 0, TYPL, 0, 0, 0, TYPQ}; 26673Shenry 27673Shenry /* 28673Shenry * type flags to Loader reference and byte lengths 29673Shenry */ 30673Shenry /*TYPB TYPW TYPL TYPQ TYPF TYPD*/ 31673Shenry int ty_NORELOC[] = /* {TYPB..TYPD} ==> {1 if relocation not OK */ 32673Shenry {0, 0, 0, 1, 1, 1}; 33673Shenry int ty_LEN[] = /* {TYPB..TYPD} ==> {LEN1..LEN8} */ 34673Shenry {LEN1, LEN2, LEN4, LEN8, LEN4, LEN8}; 35673Shenry int ty_nbyte[] = /* {TYPB..TYPD} ==> {1,2,4,8} */ 36673Shenry {1, 2, 4, 8, 4, 8}; 37673Shenry int ty_nlg[] = /* {TYPB..TYPD} ==> lg{1,2,4,8} */ 38673Shenry {0, 1, 2, 3, 2, 3}; 39673Shenry 40592Sbill insout(op, ap, nact) 41592Sbill struct arg *ap; 42592Sbill { 43667Shenry int jxxflg; 44667Shenry register struct instab *ip; /* the instruction */ 45667Shenry register struct arg *ap_walk; /* actual param walk */ 46667Shenry register int i; 47667Shenry register int ap_type; /* actual param type */ 48667Shenry register int ap_type_mask; /* masked actual param */ 49592Sbill op &= 0xFF; 50592Sbill jxxflg = nact; 51592Sbill if (nact < 0) 52592Sbill nact = -nact; 53592Sbill if (passno == 1) { 54667Shenry ip = itab[op]; 55667Shenry if (nact < ip->i_nargs) 56667Shenry yyerror("Too few arguments"); 57667Shenry if (nact > ip->i_nargs) { 58667Shenry yyerror("Too many arguments"); 59667Shenry nact = ip->i_nargs; 60667Shenry } 61667Shenry /* 62667Shenry * Check argument compatability with instruction template 63667Shenry */ 64667Shenry for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){ 65673Shenry ap_type = ap_walk->a_atype; 66667Shenry ap_type_mask = ap_type & AMASK; 67*1746Shenry /* 68*1746Shenry * The switch value is >> by 3 so that the switch 69*1746Shenry * code is dense, not implemented as a sequence 70*1746Shenry * of branches but implemented as a casel. 71*1746Shenry * In addition, cases ACCI and ACCR are added to force 72*1746Shenry * dense switch code. 73*1746Shenry */ 74*1746Shenry switch( ((fetcharg(ip, i-1)) & ACCESSMASK)>>3){ /* type of fp */ 75*1746Shenry case ACCI >> 3: 76*1746Shenry case ACCR >> 3: 77*1746Shenry break; 78*1746Shenry case ACCB >> 3: 79667Shenry if ( !((ap_type_mask == AEXP) || (ap_type_mask == AIMM)) ){ 80667Shenry yyerror("arg %d, branch displacement must be an expression",i); 81667Shenry return; 82667Shenry } 83667Shenry break; 84*1746Shenry case ACCA >> 3: 85667Shenry switch(ap_type_mask){ 86667Shenry case AREG: yyerror("arg %d, addressing a register",i); 87667Shenry return; 88667Shenry case AIMM: if ( !(ap_type & ASTAR) ){ 89667Shenry yyerror("arg %d, addressing an immediate operand",i); 90667Shenry return; 91667Shenry } 92667Shenry } 93667Shenry break; 94*1746Shenry case ACCM >> 3: 95*1746Shenry case ACCW >> 3: 96667Shenry switch(ap_type_mask){ 97667Shenry case AIMM: if (!(ap_type&ASTAR)) { 98667Shenry yyerror("arg %d, modifying a constant",i); 99667Shenry return; 100667Shenry } 101667Shenry } 102667Shenry break; 103667Shenry } /* end of the switch on fp_type */ 104667Shenry if (ap_type & AINDX) { 105667Shenry if (ap_walk->a_areg2==0xF) { 106667Shenry yyerror("arg %d, PC used as index",i); 107667Shenry return; 108667Shenry } 109667Shenry switch(ap_type_mask){ 110667Shenry case AREG: yyerror("arg %d, indexing the register file",i); 111667Shenry return; 112667Shenry case AIMM: yyerror("arg %d, indexing a constant",i); 113667Shenry return; 114673Shenry case ADECR: 115673Shenry case AINCR: if (ap_walk->a_areg1==ap_walk->a_areg2) { 116667Shenry yyerror("arg %d, indexing with modified register",i); 117667Shenry return; 118667Shenry } 119667Shenry break; 120667Shenry } /* end of switch on ap_type_mask */ 121667Shenry } /* end of AINDX */ 122667Shenry } 123667Shenry } /* both passes here */ 124592Sbill if (jxxflg < 0) 125592Sbill ijxout(op, ap, nact); 126592Sbill else putins(op, ap, nact); 127592Sbill } 128592Sbill 129592Sbill extern int d124; 130592Sbill 131592Sbill putins(op, ap, n) 132592Sbill /* 133592Sbill * n had better be positive 134592Sbill */ 135592Sbill register struct arg *ap; 136592Sbill { 137592Sbill register struct exp *xp; 138853Shenry register int argtype; 139673Shenry int i; 140673Shenry int reloc_how; 141592Sbill 142592Sbill #ifdef DEBUG 143592Sbill fflush(stdout); 144592Sbill #endif 145592Sbill if (passno == 2) 146592Sbill goto PASS2; 147592Sbill 148629Shenry dotp->e_xvalue += n+1; /* 1 for the opcode, at least 1 per arg */ 149629Shenry for (i=0; i<n; i++,ap++) { /* some args take more than 1 byte */ 150853Shenry argtype = ap->a_atype; 151853Shenry if (argtype & AINDX) 152629Shenry dotp->e_xvalue++; 153*1746Shenry /* 154*1746Shenry * This switch has been fixed by enumerating the no action 155*1746Shenry * alternatives (those that have 1 one byte of code) 156*1746Shenry * so that a casel instruction is emitted. 157*1746Shenry */ 158853Shenry switch (argtype&~(AINDX|ASTAR)) { 159*1746Shenry case AREG: 160*1746Shenry case ABASE: 161*1746Shenry case ADECR: 162*1746Shenry case AINCR: 163*1746Shenry break; 164592Sbill case AEXP: 165853Shenry argtype = fetcharg(itab[op], i); 166853Shenry if (argtype == ACCB+TYPB) 167592Sbill break; 168853Shenry if (argtype==ACCB+TYPW){ 169629Shenry dotp->e_xvalue++; 170592Sbill break; 171592Sbill } 172592Sbill /* 173592Sbill * Reduces to PC relative 174592Sbill */ 175629Shenry dotp->e_xvalue += ap->a_dispsize; 176592Sbill break; 177592Sbill 178592Sbill case ADISP: 179629Shenry xp=ap->a_xp; 180629Shenry if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){ 181629Shenry dotp->e_xvalue += ap->a_dispsize; 182592Sbill break; 183592Sbill } 184853Shenry if (xp->e_xvalue==0 && !(argtype&ASTAR)) 185592Sbill break; 186629Shenry dotp->e_xvalue++; 187629Shenry if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)) 188629Shenry dotp->e_xvalue++; 189629Shenry if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)) 190629Shenry dotp->e_xvalue += 2; 191592Sbill break; 192592Sbill 193592Sbill case AIMM: 194853Shenry if (ap->a_atype&ASTAR) argtype=TYPL; 195592Sbill else { 196853Shenry argtype = fetcharg(itab[op], i); 197853Shenry if (argtype&ACCA) 198853Shenry argtype = TYPL; 199592Sbill else 200853Shenry argtype &= TYPMASK; 201629Shenry xp = ap->a_xp; 202629Shenry if ( ((xp->e_xtype&XTYPE)==XABS) 203629Shenry && (!(xp->e_xtype&XFORW)) 204629Shenry && (xp->e_xvalue>=0) 205629Shenry && (xp->e_xvalue<=63) 206629Shenry && (xp->e_yvalue == 0) 207853Shenry && (argtype != TYPD) 208853Shenry && (argtype != TYPF) 209592Sbill ) 210592Sbill break; 211592Sbill } 212853Shenry switch (argtype) { 213592Sbill case TYPD: 214592Sbill case TYPF: 215629Shenry if ( !(((xp->e_xtype&XTYPE)==XABS) 216629Shenry && (!(xp->e_xtype&XFORW)) 217592Sbill && (slitflt(xp))) 218592Sbill ){ 219592Sbill /* it is NOT short */ 220853Shenry dotp->e_xvalue += ((argtype==TYPF)? 221592Sbill 4 : 8); 222592Sbill } 223592Sbill break; 224592Sbill case TYPQ: 225629Shenry dotp->e_xvalue += 8;break; 226592Sbill case TYPL: 227629Shenry dotp->e_xvalue += 4;break; 228592Sbill case TYPW: 229629Shenry dotp->e_xvalue += 2;break; 230592Sbill case TYPB: 231629Shenry dotp->e_xvalue += 1;break; 232853Shenry } /*end of the switch on argtype*/ 233592Sbill } /*end of the switch on the type*/ 234592Sbill } /*end of looping for all arguments*/ 235592Sbill return; 236592Sbill 237592Sbill PASS2: 238592Sbill 239592Sbill #ifdef UNIX 240592Sbill outb(op); /* the opcode */ 241592Sbill #endif UNIX 242592Sbill #ifdef VMS 243592Sbill *vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)op; 244629Shenry dotp->e_xvalue += 1; 245592Sbill #endif VMS 246592Sbill 247592Sbill for (i=0; i<n; i++,ap++) {/* now for the arguments */ 248853Shenry argtype=ap->a_atype; 249629Shenry xp=ap->a_xp; 250673Shenry reloc_how = TYPNONE; 251853Shenry if (argtype&AINDX) { 252592Sbill #ifdef UNIX 253629Shenry { outb(0x40 | ap->a_areg2); } 254592Sbill #endif UNIX 255592Sbill #ifdef VMS 256592Sbill { *vms_obj_ptr++ = -1; 257629Shenry *vms_obj_ptr++ = (0x40 | ap->a_areg2); 258629Shenry dotp->e_xvalue += 1; } 259592Sbill #endif VMS 260853Shenry argtype &= ~AINDX; 261592Sbill } 262853Shenry if (argtype&ASTAR) { 263629Shenry ap->a_areg1 |= 0x10; 264853Shenry argtype &= ~ASTAR; 265592Sbill } 266853Shenry switch (argtype) { 267592Sbill case AREG: /* %r */ 268629Shenry ap->a_areg1 |= 0x50; 269592Sbill break; 270592Sbill case ABASE: /* (%r) */ 271629Shenry ap->a_areg1 |= 0x60; 272592Sbill break; 273592Sbill case ADECR: /* -(%r) */ 274629Shenry ap->a_areg1 |= 0x70; 275592Sbill break; 276665Shenry case AINCR: /* (%r)+ */ 277629Shenry ap->a_areg1 |= 0x80; 278592Sbill break; 279592Sbill case AEXP: /* expr */ 280853Shenry argtype = fetcharg(itab[op], i); 281853Shenry if (argtype == ACCB+TYPB) { 282853Shenry ap->a_areg1 = argtype = 283629Shenry xp->e_xvalue - (dotp->e_xvalue + 1); 284853Shenry if (argtype<MINBYTE || argtype>MAXBYTE) 285592Sbill yyerror("Branch too far"); break; 286592Sbill } 287853Shenry if (argtype == ACCB+TYPW) { 288853Shenry ap->a_areg1 = argtype = xp->e_xvalue 289629Shenry -= dotp->e_xvalue + 2; 290629Shenry xp->e_xtype = XABS; 291853Shenry if (argtype<MINWORD || argtype>MAXWORD) 292592Sbill yyerror("Branch too far"); 293853Shenry xp->e_xvalue = argtype>>8; 294673Shenry reloc_how = TYPB; 295592Sbill break; 296592Sbill } 297592Sbill /* reduces to expr(pc) mode */ 298629Shenry ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]); 299673Shenry reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL; 300592Sbill break; 301592Sbill 302592Sbill case ADISP: /* expr(%r) */ 303629Shenry ap->a_areg1 |= 0xA0; 304629Shenry if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){ 305629Shenry ap->a_areg1 += mod124[ap->a_dispsize]; 306673Shenry reloc_how = type_124[ap->a_dispsize]; 307592Sbill break; 308592Sbill } 309629Shenry if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) { 310629Shenry ap->a_areg1 ^= 0xC0; 311592Sbill break; 312592Sbill } 313673Shenry reloc_how = TYPB; 314629Shenry if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)){ 315629Shenry ap->a_areg1 += 0x20; 316673Shenry reloc_how = TYPW; 317592Sbill } 318629Shenry if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)){ 319629Shenry ap->a_areg1 += 0x20; 320673Shenry reloc_how = TYPL; 321592Sbill } 322592Sbill break; 323592Sbill 324592Sbill case AIMM: /* $expr */ 325629Shenry if (ap->a_atype&ASTAR) 326853Shenry argtype=TYPL; 327592Sbill else { 328853Shenry argtype = fetcharg(itab[op], i); 329853Shenry if (argtype&ACCA) 330853Shenry argtype=TYPL; 331592Sbill else 332853Shenry argtype &= TYPMASK; 333629Shenry if ( ( (xp->e_xtype&XTYPE) == XABS) 334629Shenry && !(xp->e_xtype&XFORW) 335629Shenry && (xp->e_xvalue >= 0) 336629Shenry && (xp->e_xvalue <= 63) 337629Shenry && (xp->e_yvalue == 0) 338853Shenry && (argtype != TYPF) 339853Shenry && (argtype != TYPD) ) { 340629Shenry ap->a_areg1 = xp->e_xvalue; 341592Sbill break; 342592Sbill } 343592Sbill } 344629Shenry ap->a_areg1 |= 0x8F; 345853Shenry reloc_how = argtype; 346673Shenry if (reloc_how == TYPD || reloc_how == TYPF){ 347629Shenry if ( ((xp->e_xtype&XTYPE)==XABS) 348629Shenry && (!(xp->e_xtype&XFORW)) 349592Sbill && (slitflt(xp)) 350592Sbill ){ 351673Shenry reloc_how = TYPNONE; 352629Shenry ap->a_areg1=extlitflt(xp); 353592Sbill } 354592Sbill } 355592Sbill break; 356592Sbill 357853Shenry } /*end of the switch on argtype*/ 358592Sbill /* 359592Sbill * use the first byte to describe the argument 360592Sbill */ 361592Sbill #ifdef UNIX 362629Shenry outb(ap->a_areg1); 363592Sbill #endif UNIX 364592Sbill #ifdef VMS 365629Shenry *vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)(ap->a_areg1); 366629Shenry dotp->e_xvalue += 1; 367592Sbill if ((vms_obj_ptr-sobuf) > 400) { 368592Sbill write(objfil,sobuf,vms_obj_ptr-sobuf); 369592Sbill vms_obj_ptr=sobuf+1; 370592Sbill } 371592Sbill #endif VMS 372673Shenry if (reloc_how != TYPNONE) 373673Shenry outrel(xp, reloc_how); 374592Sbill } /*end of the for to pick up all arguments*/ 375592Sbill } 376