/* 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" /* * 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; { 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; 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; /* * 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. */ 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); } extern int d124; putins(op, ap, n) /* * n had better be positive */ register struct arg *ap; { register struct exp *xp; register int argtype; int i; int reloc_how; #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; } 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); } 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 */ #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 */ 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 (argtype&ASTAR) { ap->a_areg1 |= 0x10; argtype &= ~ASTAR; } 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; } /* 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; } if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) { ap->a_areg1 ^= 0xC0; break; } 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->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); } } break; } /*end of the switch on argtype*/ /* * use the first byte to describe the argument */ #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*/ }