| 1 | /* Copyright (c) 1980 Regents of the University of California */ |
| 2 | static char sccsid[] = "@(#)ascode.c 4.3 %G%"; |
| 3 | #include <stdio.h> |
| 4 | #include "as.h" |
| 5 | #include "assyms.h" |
| 6 | |
| 7 | insout(op, ap, nact) |
| 8 | struct arg *ap; |
| 9 | { |
| 10 | int jxxflg; |
| 11 | |
| 12 | op &= 0xFF; |
| 13 | jxxflg = nact; |
| 14 | if (nact < 0) |
| 15 | nact = -nact; |
| 16 | if (passno == 1) { |
| 17 | register struct arg *ap2; |
| 18 | register struct instab *ip; |
| 19 | int i,nexp; |
| 20 | ip = itab[op]; |
| 21 | nexp = ip->i_nargs; |
| 22 | if (nact < nexp) |
| 23 | yyerror("Too few arguments"); |
| 24 | if (nact > nexp) { |
| 25 | yyerror("Too many arguments"); |
| 26 | nact = nexp; |
| 27 | } |
| 28 | /* |
| 29 | * Check argument compatability with instruction template |
| 30 | */ |
| 31 | for (ap2 = ap+nact, i = nact; --i >= 0;) |
| 32 | argcompat(--ap2, fetcharg(ip, i), i+1); |
| 33 | } |
| 34 | if (jxxflg < 0) |
| 35 | ijxout(op, ap, nact); |
| 36 | else putins(op, ap, nact); |
| 37 | } |
| 38 | |
| 39 | argcompat(act, exp, i) |
| 40 | struct arg *act; |
| 41 | int exp,i; |
| 42 | { |
| 43 | register at,atm; |
| 44 | |
| 45 | at = act->a_atype; |
| 46 | atm = at & AMASK; |
| 47 | |
| 48 | if ( (exp & ACCB) && (!((atm == AEXP) || (atm == AIMM))) ){ |
| 49 | yyerror("arg %d, branch displacement must be an expression",i); |
| 50 | return; |
| 51 | } |
| 52 | if (exp & ACCA){ |
| 53 | if (atm == AREG) { |
| 54 | yyerror("arg %d, addressing a register",i); |
| 55 | return; |
| 56 | } |
| 57 | if ( (atm == AIMM) && !(at & ASTAR) ){ |
| 58 | yyerror("arg %d, addressing an immediate operand",i); |
| 59 | return; |
| 60 | } |
| 61 | } |
| 62 | if ((exp&ACCW) && (atm==AIMM) && !(at&ASTAR)) { |
| 63 | yyerror("arg %d, modifying a constant",i); |
| 64 | return; |
| 65 | } |
| 66 | if (at & AINDX) { |
| 67 | if (act->a_areg2==017) { |
| 68 | yyerror("arg %d, PC used as index",i); |
| 69 | return; |
| 70 | } |
| 71 | if (atm==AREG) { |
| 72 | yyerror("arg %d, indexing the register file",i); |
| 73 | return; |
| 74 | } |
| 75 | if (atm==AIMM) { |
| 76 | yyerror("arg %d, indexing a constant",i); |
| 77 | return; |
| 78 | } |
| 79 | if (((atm==ADECR) || (atm==AINCR)) && (act->a_areg1==act->a_areg2)) { |
| 80 | yyerror("arg %d, indexing with modified register",i); |
| 81 | return; |
| 82 | } |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | extern int d124; |
| 87 | int len124[] = {0,LEN1,LEN2,0,LEN4}; |
| 88 | char mod124[] = {0,0x00,0x20,0,0x40}; |
| 89 | |
| 90 | putins(op, ap, n) |
| 91 | /* |
| 92 | * n had better be positive |
| 93 | */ |
| 94 | register struct arg *ap; |
| 95 | { |
| 96 | register struct exp *xp; |
| 97 | register int a; |
| 98 | int i,xtrab; |
| 99 | |
| 100 | #ifdef DEBUG |
| 101 | fflush(stdout); |
| 102 | #endif |
| 103 | if (passno == 2) |
| 104 | goto PASS2; |
| 105 | |
| 106 | dotp->e_xvalue += n+1; /* 1 for the opcode, at least 1 per arg */ |
| 107 | for (i=0; i<n; i++,ap++) { /* some args take more than 1 byte */ |
| 108 | a = ap->a_atype; |
| 109 | if (a & AINDX) |
| 110 | dotp->e_xvalue++; |
| 111 | switch (a&~(AINDX|ASTAR)) { |
| 112 | case AEXP: |
| 113 | a = fetcharg(itab[op], i); |
| 114 | if (a == ACCB+TYPB) |
| 115 | break; |
| 116 | if (a==ACCB+TYPW){ |
| 117 | dotp->e_xvalue++; |
| 118 | break; |
| 119 | } |
| 120 | /* |
| 121 | * Reduces to PC relative |
| 122 | */ |
| 123 | dotp->e_xvalue += ap->a_dispsize; |
| 124 | break; |
| 125 | |
| 126 | case ADISP: |
| 127 | xp=ap->a_xp; |
| 128 | if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){ |
| 129 | dotp->e_xvalue += ap->a_dispsize; |
| 130 | break; |
| 131 | } |
| 132 | if (xp->e_xvalue==0 && !(a&ASTAR)) |
| 133 | break; |
| 134 | dotp->e_xvalue++; |
| 135 | if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)) |
| 136 | dotp->e_xvalue++; |
| 137 | if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)) |
| 138 | dotp->e_xvalue += 2; |
| 139 | break; |
| 140 | |
| 141 | case AIMM: |
| 142 | if (ap->a_atype&ASTAR) a=TYPL; |
| 143 | else { |
| 144 | a = fetcharg(itab[op], i); |
| 145 | if (a&ACCA) |
| 146 | a = TYPL; |
| 147 | else |
| 148 | a &= TYPMASK; |
| 149 | xp = ap->a_xp; |
| 150 | if ( ((xp->e_xtype&XTYPE)==XABS) |
| 151 | && (!(xp->e_xtype&XFORW)) |
| 152 | && (xp->e_xvalue>=0) |
| 153 | && (xp->e_xvalue<=63) |
| 154 | && (xp->e_yvalue == 0) |
| 155 | && (a != TYPD) |
| 156 | && (a != TYPF) |
| 157 | ) |
| 158 | break; |
| 159 | } |
| 160 | switch (a) { |
| 161 | case TYPD: |
| 162 | case TYPF: |
| 163 | if ( !(((xp->e_xtype&XTYPE)==XABS) |
| 164 | && (!(xp->e_xtype&XFORW)) |
| 165 | && (slitflt(xp))) |
| 166 | ){ |
| 167 | /* it is NOT short */ |
| 168 | dotp->e_xvalue += ((a==TYPF)? |
| 169 | 4 : 8); |
| 170 | } |
| 171 | break; |
| 172 | case TYPQ: |
| 173 | dotp->e_xvalue += 8;break; |
| 174 | case TYPL: |
| 175 | dotp->e_xvalue += 4;break; |
| 176 | case TYPW: |
| 177 | dotp->e_xvalue += 2;break; |
| 178 | case TYPB: |
| 179 | dotp->e_xvalue += 1;break; |
| 180 | } /*end of the switch on a*/ |
| 181 | } /*end of the switch on the type*/ |
| 182 | } /*end of looping for all arguments*/ |
| 183 | return; |
| 184 | |
| 185 | PASS2: |
| 186 | |
| 187 | #ifdef UNIX |
| 188 | outb(op); /* the opcode */ |
| 189 | #endif UNIX |
| 190 | #ifdef VMS |
| 191 | *vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)op; |
| 192 | dotp->e_xvalue += 1; |
| 193 | #endif VMS |
| 194 | |
| 195 | for (i=0; i<n; i++,ap++) {/* now for the arguments */ |
| 196 | a=ap->a_atype; |
| 197 | xp=ap->a_xp; |
| 198 | xtrab=0; |
| 199 | if (a&AINDX) { |
| 200 | #ifdef UNIX |
| 201 | { outb(0x40 | ap->a_areg2); } |
| 202 | #endif UNIX |
| 203 | #ifdef VMS |
| 204 | { *vms_obj_ptr++ = -1; |
| 205 | *vms_obj_ptr++ = (0x40 | ap->a_areg2); |
| 206 | dotp->e_xvalue += 1; } |
| 207 | #endif VMS |
| 208 | a &= ~AINDX; |
| 209 | } |
| 210 | if (a&ASTAR) { |
| 211 | ap->a_areg1 |= 0x10; |
| 212 | a &= ~ASTAR; |
| 213 | } |
| 214 | switch (a) { |
| 215 | case AREG: /* %r */ |
| 216 | ap->a_areg1 |= 0x50; |
| 217 | break; |
| 218 | case ABASE: /* (%r) */ |
| 219 | ap->a_areg1 |= 0x60; |
| 220 | break; |
| 221 | case ADECR: /* -(%r) */ |
| 222 | ap->a_areg1 |= 0x70; |
| 223 | break; |
| 224 | case AINCR: /* (%r)+ */ |
| 225 | ap->a_areg1 |= 0x80; |
| 226 | break; |
| 227 | case AEXP: /* expr */ |
| 228 | a = fetcharg(itab[op], i); |
| 229 | if (a == ACCB+TYPB) { |
| 230 | ap->a_areg1 = a = |
| 231 | xp->e_xvalue - (dotp->e_xvalue + 1); |
| 232 | if (a<MINBYTE || a>MAXBYTE) |
| 233 | yyerror("Branch too far"); break; |
| 234 | } |
| 235 | if (a == ACCB+TYPW) { |
| 236 | ap->a_areg1 = a = xp->e_xvalue |
| 237 | -= dotp->e_xvalue + 2; |
| 238 | xp->e_xtype = XABS; |
| 239 | if (a<MINWORD || a>MAXWORD) |
| 240 | yyerror("Branch too far"); |
| 241 | xp->e_xvalue = a>>8; |
| 242 | xtrab = LEN1; |
| 243 | break; |
| 244 | } |
| 245 | /* reduces to expr(pc) mode */ |
| 246 | ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]); |
| 247 | xtrab = len124[ap->a_dispsize]+PCREL; |
| 248 | break; |
| 249 | |
| 250 | case ADISP: /* expr(%r) */ |
| 251 | ap->a_areg1 |= 0xA0; |
| 252 | if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){ |
| 253 | ap->a_areg1 += mod124[ap->a_dispsize]; |
| 254 | xtrab=len124[ap->a_dispsize]; |
| 255 | break; |
| 256 | } |
| 257 | if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) { |
| 258 | ap->a_areg1 ^= 0xC0; |
| 259 | break; |
| 260 | } |
| 261 | xtrab=LEN1; |
| 262 | if ((xp->e_xvalue<MINBYTE) || (xp->e_xvalue>MAXBYTE)){ |
| 263 | ap->a_areg1 += 0x20; |
| 264 | xtrab=LEN2; |
| 265 | } |
| 266 | if ((xp->e_xvalue<MINWORD) || (xp->e_xvalue>MAXWORD)){ |
| 267 | ap->a_areg1 += 0x20; |
| 268 | xtrab=LEN4; |
| 269 | } |
| 270 | break; |
| 271 | |
| 272 | case AIMM: /* $expr */ |
| 273 | if (ap->a_atype&ASTAR) |
| 274 | a=TYPL; |
| 275 | else { |
| 276 | a = fetcharg(itab[op], i); |
| 277 | if (a&ACCA) |
| 278 | a=TYPL; |
| 279 | else |
| 280 | a &= TYPMASK; |
| 281 | if ( ( (xp->e_xtype&XTYPE) == XABS) |
| 282 | && !(xp->e_xtype&XFORW) |
| 283 | && (xp->e_xvalue >= 0) |
| 284 | && (xp->e_xvalue <= 63) |
| 285 | && (xp->e_yvalue == 0) |
| 286 | && (a != TYPF) |
| 287 | && (a != TYPD) ) { |
| 288 | ap->a_areg1 = xp->e_xvalue; |
| 289 | break; |
| 290 | } |
| 291 | } |
| 292 | ap->a_areg1 |= 0x8F; |
| 293 | switch (a) { |
| 294 | case TYPD: |
| 295 | case TYPF: |
| 296 | if ( ((xp->e_xtype&XTYPE)==XABS) |
| 297 | && (!(xp->e_xtype&XFORW)) |
| 298 | && (slitflt(xp)) |
| 299 | ){ |
| 300 | ap->a_areg1=extlitflt(xp); |
| 301 | } else { |
| 302 | xtrab = (a==TYPF) ? LEN4: LEN8; |
| 303 | } |
| 304 | break; |
| 305 | case TYPQ: xtrab = LEN8; break; |
| 306 | case TYPL: xtrab = LEN4; break; |
| 307 | case TYPW: xtrab = LEN2; break; |
| 308 | case TYPB: xtrab = LEN1; break; |
| 309 | } |
| 310 | break; |
| 311 | |
| 312 | } /*end of the switch on a*/ |
| 313 | /* |
| 314 | * use the first byte to describe the argument |
| 315 | */ |
| 316 | #ifdef UNIX |
| 317 | outb(ap->a_areg1); |
| 318 | #endif UNIX |
| 319 | #ifdef VMS |
| 320 | *vms_obj_ptr++ = -1; *vms_obj_ptr++ = (char)(ap->a_areg1); |
| 321 | dotp->e_xvalue += 1; |
| 322 | if ((vms_obj_ptr-sobuf) > 400) { |
| 323 | write(objfil,sobuf,vms_obj_ptr-sobuf); |
| 324 | vms_obj_ptr=sobuf+1; |
| 325 | } |
| 326 | #endif VMS |
| 327 | if (xtrab) |
| 328 | /* |
| 329 | * Floating point numbers are written to a.out |
| 330 | * by outrel; they require that the least significant |
| 331 | * 4 bytes of an 8 byte double precision number |
| 332 | * immediately follow the field xvalue, which |
| 333 | * they do. |
| 334 | */ |
| 335 | outrel(&xp->e_xvalue, xtrab, xp->e_xtype, xp->e_xname); |
| 336 | } /*end of the for to pick up all arguments*/ |
| 337 | } |