15822Srrh /* 25822Srrh * Copyright (c) 1982 Regents of the University of California 35822Srrh */ 45822Srrh #ifndef lint 5*16764Sralph static char sccsid[] = "@(#)ascode.c 4.12 07/25/84"; 65822Srrh #endif not lint 75822Srrh 8592Sbill #include <stdio.h> 9592Sbill #include "as.h" 10592Sbill #include "assyms.h" 11592Sbill 125822Srrh insout(opcode, ap, nact) 135822Srrh struct Opcode opcode; 145822Srrh struct arg *ap; 155822Srrh int nact; 165822Srrh { 175822Srrh int jxxflg; 185822Srrh reg struct instab *ip; /* the instruction */ 195822Srrh reg struct arg *ap_walk; /* actual param walk */ 205822Srrh reg int i; 215822Srrh reg int ap_type; /* actual param type */ 225822Srrh reg int ap_type_mask; /* masked actual param */ 23673Shenry 24592Sbill jxxflg = nact; 25592Sbill if (nact < 0) 26592Sbill nact = -nact; 27592Sbill if (passno == 1) { 285822Srrh if (!(ITABCHECK(opcode))) 295822Srrh panic("Botched reference into itab"); 305822Srrh ip = ITABFETCH(opcode); 315822Srrh if (nact < ip->i_nargs) 325822Srrh yyerror("Too few arguments"); 335822Srrh if (nact > ip->i_nargs) { 345822Srrh yyerror("Too many arguments"); 355822Srrh nact = ip->i_nargs; 365822Srrh } 37667Shenry /* 38667Shenry * Check argument compatability with instruction template 39667Shenry */ 40667Shenry for (ap_walk = ap, i = 1; i <= nact; ap_walk++, i++){ 41673Shenry ap_type = ap_walk->a_atype; 42667Shenry ap_type_mask = ap_type & AMASK; 431746Shenry /* 445822Srrh * The switch value is >> by TYPLG so that the switch 451746Shenry * code is dense, not implemented as a sequence 461746Shenry * of branches but implemented as a casel. 471746Shenry * In addition, cases ACCI and ACCR are added to force 481746Shenry * dense switch code. 495822Srrh * switch on the type of fp 501746Shenry */ 515822Srrh switch( ((fetcharg(ip, i-1)) & ACCESSMASK) >> TYPLG){ 525822Srrh case ACCI >> TYPLG: 535822Srrh case ACCR >> TYPLG: 541746Shenry break; 555822Srrh case ACCB >> TYPLG: 56667Shenry if ( !((ap_type_mask == AEXP) || (ap_type_mask == AIMM)) ){ 57667Shenry yyerror("arg %d, branch displacement must be an expression",i); 58667Shenry return; 59667Shenry } 60667Shenry break; 615822Srrh case ACCA >> TYPLG: 62667Shenry switch(ap_type_mask){ 63667Shenry case AREG: yyerror("arg %d, addressing a register",i); 64667Shenry return; 65667Shenry case AIMM: if ( !(ap_type & ASTAR) ){ 66667Shenry yyerror("arg %d, addressing an immediate operand",i); 67667Shenry return; 68667Shenry } 69667Shenry } 70667Shenry break; 715822Srrh case ACCM >> TYPLG: 725822Srrh case ACCW >> TYPLG: 73667Shenry switch(ap_type_mask){ 74667Shenry case AIMM: if (!(ap_type&ASTAR)) { 75667Shenry yyerror("arg %d, modifying a constant",i); 76667Shenry return; 77667Shenry } 78667Shenry } 79667Shenry break; 80667Shenry } /* end of the switch on fp_type */ 81667Shenry if (ap_type & AINDX) { 82667Shenry if (ap_walk->a_areg2==0xF) { 83667Shenry yyerror("arg %d, PC used as index",i); 84667Shenry return; 85667Shenry } 86667Shenry switch(ap_type_mask){ 87667Shenry case AREG: yyerror("arg %d, indexing the register file",i); 88667Shenry return; 89667Shenry case AIMM: yyerror("arg %d, indexing a constant",i); 90667Shenry return; 91673Shenry case ADECR: 92673Shenry case AINCR: if (ap_walk->a_areg1==ap_walk->a_areg2) { 93667Shenry yyerror("arg %d, indexing with modified register",i); 94667Shenry return; 95667Shenry } 96667Shenry break; 97667Shenry } /* end of switch on ap_type_mask */ 98667Shenry } /* end of AINDX */ 99667Shenry } 100667Shenry } /* both passes here */ 101592Sbill if (jxxflg < 0) 1025822Srrh ijxout(opcode, ap, nact); 1035822Srrh else 1045822Srrh putins(opcode, ap, nact); 105592Sbill } 106592Sbill 107592Sbill extern int d124; 108592Sbill 1095822Srrh putins(opcode, ap, n) 1105822Srrh struct Opcode opcode; 111592Sbill register struct arg *ap; 1125822Srrh int n; /* Must be positive */ 113592Sbill { 1145822Srrh reg struct exp *xp; 1155822Srrh reg int argtype; 1165822Srrh int i; 1175822Srrh int reloc_how; 1185822Srrh int value; 119592Sbill 120592Sbill #ifdef DEBUG 121592Sbill fflush(stdout); 122592Sbill #endif 123592Sbill if (passno == 2) 124592Sbill goto PASS2; 125592Sbill 1265822Srrh dotp->e_xvalue += n; /* at least one byte per arg */ 1275822Srrh switch(opcode.Op_eopcode){ 1285822Srrh case NEW: 1295822Srrh case CORE: 1305822Srrh dotp->e_xvalue += 1; /* 1 byte opcode */ 1315822Srrh break; 1325822Srrh case ESCD: 1335822Srrh case ESCF: 1345822Srrh dotp->e_xvalue += 2; /* 2 byte opcode */ 1355822Srrh break; 1365822Srrh default: 1375822Srrh panic("Bad escape opcode"); 1385822Srrh } 1395822Srrh 140629Shenry for (i=0; i<n; i++,ap++) { /* some args take more than 1 byte */ 141853Shenry argtype = ap->a_atype; 142853Shenry if (argtype & AINDX) 143629Shenry dotp->e_xvalue++; 1441746Shenry /* 1451746Shenry * This switch has been fixed by enumerating the no action 1461746Shenry * alternatives (those that have 1 one byte of code) 1471746Shenry * so that a casel instruction is emitted. 1481746Shenry */ 149853Shenry switch (argtype&~(AINDX|ASTAR)) { 1501746Shenry case AREG: 1511746Shenry case ABASE: 1521746Shenry case ADECR: 1531746Shenry case AINCR: 1541746Shenry break; 155592Sbill case AEXP: 1565822Srrh argtype = fetcharg(ITABFETCH(opcode), i); 1575822Srrh if (argtype == A_BB) 158592Sbill break; 1595822Srrh if (argtype == A_BW){ 160629Shenry dotp->e_xvalue++; 161592Sbill break; 162592Sbill } 163592Sbill /* 164592Sbill * Reduces to PC relative 165592Sbill */ 166629Shenry dotp->e_xvalue += ap->a_dispsize; 167592Sbill break; 168592Sbill 169592Sbill case ADISP: 170629Shenry xp=ap->a_xp; 171629Shenry if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){ 172629Shenry dotp->e_xvalue += ap->a_dispsize; 173592Sbill break; 174592Sbill } 175853Shenry if (xp->e_xvalue==0 && !(argtype&ASTAR)) 176592Sbill break; 1775822Srrh dotp->e_xvalue += 1; 1785822Srrh if (ISBYTE(xp->e_xvalue)) 1795822Srrh break; 1805822Srrh dotp->e_xvalue += 1; 1815822Srrh if (ISWORD(xp->e_xvalue)) 1825822Srrh break; 1835822Srrh dotp->e_xvalue += 2; 184592Sbill break; 185592Sbill 186592Sbill case AIMM: 1875822Srrh if (ap->a_atype&ASTAR) { 1885822Srrh argtype=TYPL; 1895822Srrh } else { 1905822Srrh argtype = fetcharg(ITABFETCH(opcode), i); 191853Shenry if (argtype&ACCA) 192853Shenry argtype = TYPL; 193592Sbill else 194853Shenry argtype &= TYPMASK; 195629Shenry xp = ap->a_xp; 1965822Srrh if (immconstant(ap->a_xp, argtype, &value)) 1975822Srrh break; 198592Sbill } 1995822Srrh dotp->e_xvalue += ty_nbyte[argtype]; 200592Sbill } /*end of the switch on the type*/ 201592Sbill } /*end of looping for all arguments*/ 202592Sbill return; 203592Sbill 204592Sbill PASS2: 2055822Srrh /* 2065822Srrh * Output the opcode 2075822Srrh */ 2085822Srrh switch(opcode.Op_eopcode){ 2095822Srrh case NEW: 2105822Srrh nnewopcodes++; 2115822Srrh break; 2125822Srrh case ESCD: 2135822Srrh case ESCF: 2145822Srrh nGHopcodes++; 2155822Srrh Outb(opcode.Op_eopcode); 2165822Srrh break; 2175822Srrh case CORE: 2185822Srrh break; 2195822Srrh default: 2205822Srrh panic("Bad escape opcode"); 2215822Srrh } 2225822Srrh Outb(opcode.Op_popcode); 223592Sbill 224592Sbill for (i=0; i<n; i++,ap++) {/* now for the arguments */ 225853Shenry argtype=ap->a_atype; 226629Shenry xp=ap->a_xp; 227673Shenry reloc_how = TYPNONE; 228853Shenry if (argtype&AINDX) { 2295822Srrh { Outb(0x40 | ap->a_areg2); } 230853Shenry argtype &= ~AINDX; 231592Sbill } 232853Shenry if (argtype&ASTAR) { 233629Shenry ap->a_areg1 |= 0x10; 234853Shenry argtype &= ~ASTAR; 235592Sbill } 236853Shenry switch (argtype) { 237592Sbill case AREG: /* %r */ 238629Shenry ap->a_areg1 |= 0x50; 239592Sbill break; 240592Sbill case ABASE: /* (%r) */ 241629Shenry ap->a_areg1 |= 0x60; 242592Sbill break; 243592Sbill case ADECR: /* -(%r) */ 244629Shenry ap->a_areg1 |= 0x70; 245592Sbill break; 246665Shenry case AINCR: /* (%r)+ */ 247629Shenry ap->a_areg1 |= 0x80; 248592Sbill break; 249592Sbill case AEXP: /* expr */ 2505822Srrh argtype = fetcharg(ITABFETCH(opcode), i); 2515822Srrh if (argtype == A_BB) { 252853Shenry ap->a_areg1 = argtype = 253629Shenry xp->e_xvalue - (dotp->e_xvalue + 1); 254*16764Sralph if ((xp->e_xtype & XTYPE) == XUNDEF) 2555822Srrh yywarning("%s: destination label is external", 25613511Srrh FETCHNAME(ITABFETCH(opcode))); 2575822Srrh if (!ISBYTE(argtype)) 25813083Srrh yyerror("%s: Branch too far(%db): try -J flag", 25913511Srrh FETCHNAME(ITABFETCH(opcode)), 2605822Srrh argtype); 2615822Srrh break; 262592Sbill } 2635822Srrh if (argtype == A_BW) { 264853Shenry ap->a_areg1 = argtype = xp->e_xvalue 265629Shenry -= dotp->e_xvalue + 2; 266*16764Sralph if ((xp->e_xtype & XTYPE) == XUNDEF) 2675822Srrh yywarning("%s: destination label is external", 26813511Srrh FETCHNAME(ITABFETCH(opcode))); 269629Shenry xp->e_xtype = XABS; 2705822Srrh if (!ISWORD(argtype)) 27113083Srrh yyerror("%s: Branch too far(%db): try -J flag", 27213511Srrh FETCHNAME(ITABFETCH(opcode)), 2735822Srrh argtype); 274853Shenry xp->e_xvalue = argtype>>8; 275673Shenry reloc_how = TYPB; 276592Sbill break; 277592Sbill } 278592Sbill /* reduces to expr(pc) mode */ 279629Shenry ap->a_areg1 |= (0xAF + mod124[ap->a_dispsize]); 280673Shenry reloc_how = type_124[ap->a_dispsize] + RELOC_PCREL; 281592Sbill break; 282592Sbill 283592Sbill case ADISP: /* expr(%r) */ 284629Shenry ap->a_areg1 |= 0xA0; 285629Shenry if ((xp->e_xtype&XTYPE)!=XABS || xp->e_xtype&XFORW){ 286629Shenry ap->a_areg1 += mod124[ap->a_dispsize]; 287673Shenry reloc_how = type_124[ap->a_dispsize]; 288592Sbill break; 289592Sbill } 290629Shenry if (xp->e_xvalue==0 && !(ap->a_areg1&0x10)) { 291629Shenry ap->a_areg1 ^= 0xC0; 292592Sbill break; 293592Sbill } 294673Shenry reloc_how = TYPB; 2955822Srrh if (ISBYTE(xp->e_xvalue)) 2965822Srrh break; 2975822Srrh ap->a_areg1 += 0x20; 2985822Srrh reloc_how = TYPW; 2995822Srrh if (ISWORD(xp->e_xvalue)) 3005822Srrh break; 3015822Srrh ap->a_areg1 += 0x20; 3025822Srrh reloc_how = TYPL; 303592Sbill break; 304592Sbill 305592Sbill case AIMM: /* $expr */ 3065822Srrh if (ap->a_atype&ASTAR) { 307853Shenry argtype=TYPL; 3085822Srrh } else { 3095822Srrh argtype = fetcharg(ITABFETCH(opcode), i); 310853Shenry if (argtype&ACCA) 3115822Srrh argtype = TYPL; 312592Sbill else 313853Shenry argtype &= TYPMASK; 3145822Srrh if (immconstant(xp, argtype, &value)){ 3155822Srrh reloc_how = TYPNONE; 3165822Srrh ap->a_areg1 = value; 317592Sbill break; 318592Sbill } 319592Sbill } 320629Shenry ap->a_areg1 |= 0x8F; 321853Shenry reloc_how = argtype; 322592Sbill break; 323592Sbill 324853Shenry } /*end of the switch on argtype*/ 325592Sbill /* 326592Sbill * use the first byte to describe the argument 327592Sbill */ 3285822Srrh Outb(ap->a_areg1); 329673Shenry if (reloc_how != TYPNONE) 330673Shenry outrel(xp, reloc_how); 331592Sbill } /*end of the for to pick up all arguments*/ 332592Sbill } 3335822Srrh /* 3345822Srrh * Is xp an immediate constant? 3355822Srrh * argtype: how the instruction will interpret the bytes 3365822Srrh * xp->e_number.num_tag ("numtype"): the kind of number given 3375822Srrh * 3385822Srrh * Use the following table: 3395822Srrh * float: TYPF, TYPD, TYPG, TYPH 3405822Srrh * quad: TYPQ, TYPO 3415822Srrh * int: TYPG, TYPW, TYPL 3425822Srrh * 3435822Srrh * numtype 3445822Srrh * argtype float quad int 3455822Srrh * 3465822Srrh * float slitflt slitflt slitflt 3475822Srrh * quad 0 0 0 3485822Srrh * int 0..63 0 0..63 3495822Srrh * 3505822Srrh * Where the table entry implies the predicate to return. 3515822Srrh */ 3525822Srrh #define IMMFLT 1 /* these flags are not used by anybody (yet) */ 3535822Srrh #define IMMINT 2 3545822Srrh 3555822Srrh int immconstant(xp, argtype, valuep) 3565822Srrh reg struct exp *xp; 3575822Srrh int argtype; 3585822Srrh int *valuep; 3595822Srrh { 3605822Srrh reg int back = 0; 3615822Srrh int numtype; 3625822Srrh reg int fits; 3635822Srrh 3645822Srrh if ((xp->e_xtype & XTYPE) != XABS) 3655822Srrh return(0); 3665822Srrh if ((xp->e_xtype & XFORW) != 0) 3675822Srrh return(0); 3685822Srrh numtype = xp->e_number.num_tag; 3695822Srrh 3705822Srrh fits = 1; 3715822Srrh if (passno == 2) switch(argtype){ 3725822Srrh case TYPB: 3735822Srrh switch(numtype){ 3745822Srrh default: fits = 0; break; 3755822Srrh case TYPB: fits = 1; break; 3765822Srrh case TYPW: 3775822Srrh case TYPL: 3785822Srrh fits = ISBYTE(xp->e_xvalue) || ISUBYTE(xp->e_xvalue); 3795822Srrh break; 3805822Srrh } 3815822Srrh break; 3825822Srrh case TYPW: 3835822Srrh switch(numtype){ 3845822Srrh default: fits = 0; break; 3855822Srrh case TYPB: 3865822Srrh case TYPW: fits = 1; break; 3875822Srrh case TYPL: 3885822Srrh fits = ISWORD(xp->e_xvalue) || ISUWORD(xp->e_xvalue); 3895822Srrh break; 3905822Srrh } 3915822Srrh break; 3925822Srrh case TYPF: 3935822Srrh if (numtype == TYPD){ /* same format for first 32 bits */ 3945822Srrh fits = 1; 3955822Srrh break; 3965822Srrh } 3975822Srrh /*FALLTHROUGH*/ 3985822Srrh default: 3995822Srrh fits = ty_nbyte[argtype] >= ty_nbyte[numtype]; 4005822Srrh } 4015822Srrh if (!fits){ 4025822Srrh yywarning("Immediate constant type %s mismatches instruction type %s", 4035822Srrh ty_string[numtype], 4045822Srrh ty_string[argtype]); 4055822Srrh } 4065822Srrh 4075822Srrh switch(argtype){ 4085822Srrh case TYPF: 4095822Srrh case TYPG: 4105822Srrh case TYPD: 4115822Srrh case TYPH: 4125822Srrh back = slitflt(xp->e_number, argtype, valuep); 4135822Srrh break; 4145822Srrh case TYPO: 4155822Srrh case TYPQ: 4165822Srrh back = 0; 4175822Srrh break; 4185822Srrh case TYPB: 4195822Srrh case TYPW: 4205822Srrh case TYPL: 4215822Srrh switch(numtype){ 4225822Srrh case TYPO: 4235822Srrh case TYPQ: 4245822Srrh back = 0; 4255822Srrh break; 4265822Srrh default: 4275822Srrh *valuep = xp->e_xvalue; 4285822Srrh back = ISLIT(xp->e_xvalue); 4295822Srrh break; 4305822Srrh } 4315822Srrh break; 4325822Srrh } 4335822Srrh return(back); 4345822Srrh } 435