15822Srrh /* 25822Srrh * Copyright (c) 1982 Regents of the University of California 35822Srrh */ 45822Srrh #ifndef lint 5*13083Srrh static char sccsid[] = "@(#)ascode.c 4.9 06/13/83"; 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); 2545822Srrh if (xp->e_xtype & XXTRN) 2555822Srrh yywarning("%s: destination label is external", 2565822Srrh ITABFETCH(opcode)->s_name); 2575822Srrh if (!ISBYTE(argtype)) 258*13083Srrh yyerror("%s: Branch too far(%db): try -J flag", 2595822Srrh ITABFETCH(opcode)->s_name, 2605822Srrh argtype); 2615822Srrh break; 262592Sbill } 2635822Srrh if (argtype == A_BW) { 264853Shenry ap->a_areg1 = argtype = xp->e_xvalue 265629Shenry -= dotp->e_xvalue + 2; 2665822Srrh if (xp->e_xtype & XXTRN) 2675822Srrh yywarning("%s: destination label is external", 2685822Srrh ITABFETCH(opcode)->s_name); 269629Shenry xp->e_xtype = XABS; 2705822Srrh if (!ISWORD(argtype)) 271*13083Srrh yyerror("%s: Branch too far(%db): try -J flag", 2725822Srrh ITABFETCH(opcode)->s_name, 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); 329592Sbill #ifdef VMS 330592Sbill if ((vms_obj_ptr-sobuf) > 400) { 331592Sbill write(objfil,sobuf,vms_obj_ptr-sobuf); 332592Sbill vms_obj_ptr=sobuf+1; 333592Sbill } 334592Sbill #endif VMS 335673Shenry if (reloc_how != TYPNONE) 336673Shenry outrel(xp, reloc_how); 337592Sbill } /*end of the for to pick up all arguments*/ 338592Sbill } 3395822Srrh /* 3405822Srrh * Is xp an immediate constant? 3415822Srrh * argtype: how the instruction will interpret the bytes 3425822Srrh * xp->e_number.num_tag ("numtype"): the kind of number given 3435822Srrh * 3445822Srrh * Use the following table: 3455822Srrh * float: TYPF, TYPD, TYPG, TYPH 3465822Srrh * quad: TYPQ, TYPO 3475822Srrh * int: TYPG, TYPW, TYPL 3485822Srrh * 3495822Srrh * numtype 3505822Srrh * argtype float quad int 3515822Srrh * 3525822Srrh * float slitflt slitflt slitflt 3535822Srrh * quad 0 0 0 3545822Srrh * int 0..63 0 0..63 3555822Srrh * 3565822Srrh * Where the table entry implies the predicate to return. 3575822Srrh */ 3585822Srrh #define IMMFLT 1 /* these flags are not used by anybody (yet) */ 3595822Srrh #define IMMINT 2 3605822Srrh 3615822Srrh int immconstant(xp, argtype, valuep) 3625822Srrh reg struct exp *xp; 3635822Srrh int argtype; 3645822Srrh int *valuep; 3655822Srrh { 3665822Srrh reg int back = 0; 3675822Srrh int numtype; 3685822Srrh reg int fits; 3695822Srrh 3705822Srrh if ((xp->e_xtype & XTYPE) != XABS) 3715822Srrh return(0); 3725822Srrh if ((xp->e_xtype & XFORW) != 0) 3735822Srrh return(0); 3745822Srrh numtype = xp->e_number.num_tag; 3755822Srrh 3765822Srrh fits = 1; 3775822Srrh if (passno == 2) switch(argtype){ 3785822Srrh case TYPB: 3795822Srrh switch(numtype){ 3805822Srrh default: fits = 0; break; 3815822Srrh case TYPB: fits = 1; break; 3825822Srrh case TYPW: 3835822Srrh case TYPL: 3845822Srrh fits = ISBYTE(xp->e_xvalue) || ISUBYTE(xp->e_xvalue); 3855822Srrh break; 3865822Srrh } 3875822Srrh break; 3885822Srrh case TYPW: 3895822Srrh switch(numtype){ 3905822Srrh default: fits = 0; break; 3915822Srrh case TYPB: 3925822Srrh case TYPW: fits = 1; break; 3935822Srrh case TYPL: 3945822Srrh fits = ISWORD(xp->e_xvalue) || ISUWORD(xp->e_xvalue); 3955822Srrh break; 3965822Srrh } 3975822Srrh break; 3985822Srrh case TYPF: 3995822Srrh if (numtype == TYPD){ /* same format for first 32 bits */ 4005822Srrh fits = 1; 4015822Srrh break; 4025822Srrh } 4035822Srrh /*FALLTHROUGH*/ 4045822Srrh default: 4055822Srrh fits = ty_nbyte[argtype] >= ty_nbyte[numtype]; 4065822Srrh } 4075822Srrh if (!fits){ 4085822Srrh yywarning("Immediate constant type %s mismatches instruction type %s", 4095822Srrh ty_string[numtype], 4105822Srrh ty_string[argtype]); 4115822Srrh } 4125822Srrh 4135822Srrh switch(argtype){ 4145822Srrh case TYPF: 4155822Srrh case TYPG: 4165822Srrh case TYPD: 4175822Srrh case TYPH: 4185822Srrh back = slitflt(xp->e_number, argtype, valuep); 4195822Srrh break; 4205822Srrh case TYPO: 4215822Srrh case TYPQ: 4225822Srrh back = 0; 4235822Srrh break; 4245822Srrh case TYPB: 4255822Srrh case TYPW: 4265822Srrh case TYPL: 4275822Srrh switch(numtype){ 4285822Srrh case TYPO: 4295822Srrh case TYPQ: 4305822Srrh back = 0; 4315822Srrh break; 4325822Srrh default: 4335822Srrh *valuep = xp->e_xvalue; 4345822Srrh back = ISLIT(xp->e_xvalue); 4355822Srrh break; 4365822Srrh } 4375822Srrh break; 4385822Srrh } 4395822Srrh return(back); 4405822Srrh } 441