1595Sbill /* Copyright (c) 1980 Regents of the University of California */ 2*636Shenry static char sccsid[] = "@(#)asjxxx.c 4.3 08/15/80"; 3595Sbill #include <stdio.h> 4595Sbill #include "as.h" 5595Sbill #include "assyms.h" 6595Sbill 7*636Shenry #define JBR 0x11 8*636Shenry #define BRW 0x31 9*636Shenry #define JMP 0x17 10595Sbill 11595Sbill /* 12595Sbill * The number of bytes to add if the jxxx must be "exploded" 13595Sbill * into the long form 14595Sbill */ 15*636Shenry #define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */ 16*636Shenry #define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */ 17*636Shenry #define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */ 18*636Shenry #define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */ 19595Sbill 20*636Shenry int jbrfsize = JBRDELTA; 21*636Shenry int jxxxfsize = JXXXDELTA; 22*636Shenry 23595Sbill /* 24595Sbill * These variables are filled by asscan.c with the 25595Sbill * last name encountered (a pointer buried in the intermediate file), 26595Sbill * and the last jxxx symbol table entry encountered. 27595Sbill */ 28595Sbill struct symtab *lastnam; 29595Sbill struct symtab *lastjxxx; 30595Sbill 31*636Shenry initijxxx() 32*636Shenry { 33*636Shenry jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA; 34*636Shenry jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA; 35*636Shenry /* 36*636Shenry * Note: ifjxxxJUMP is set, then we do NOT do any tunnelling; 37*636Shenry * this was too complicated to figure out, and in the first 38*636Shenry * version of the assembler, tunnelling proved to be the hardest 39*636Shenry * to get to work! 40*636Shenry */ 41*636Shenry } 42595Sbill /* 43595Sbill * Handle jxxx instructions 44595Sbill */ 45595Sbill ijxout(op,ap,nact) 46595Sbill struct arg *ap; 47595Sbill { 48595Sbill if (passno == 1){ 49595Sbill /* 50595Sbill * READ THIS BEFORE LOOKING AT jxxxfix() 51595Sbill * 52595Sbill * Record the jxxx in a special symbol table entry 53595Sbill */ 54595Sbill register struct symtab *jumpfrom; 55595Sbill 56595Sbill /* 57595Sbill * We assume the MINIMAL length 58595Sbill */ 59595Sbill putins(op,ap,nact); 60595Sbill jumpfrom = lastjxxx; 61630Shenry jumpfrom->s_tag = JXACTIVE; 62630Shenry jumpfrom->s_jxbump = 0; 63595Sbill if (op == JBR) 64*636Shenry jumpfrom->s_jxfear = jbrfsize; 65595Sbill else 66*636Shenry jumpfrom->s_jxfear = jxxxfsize; 67595Sbill if (lastnam == 0) 68595Sbill yyerror("jxxx destination not a label"); 69630Shenry jumpfrom->s_dest = lastnam; 70630Shenry jumpfrom->s_type = dotp->e_xtype; /*only TEXT or DATA*/ 71630Shenry jumpfrom->s_index = dotp-usedot; 72595Sbill /* 73595Sbill * value ALWAYS (ALWAYS!!!) indexes the next instruction 74595Sbill * after the jump, even in the jump must be exploded 75595Sbill * (bumped) 76595Sbill */ 77630Shenry jumpfrom->s_value = dotp->e_xvalue; 78595Sbill njxxx++; 79595Sbill } else {/* pass2, resolve */ 80595Sbill /* 81595Sbill * READ THIS AFTER LOOKING AT jxxxfix() 82595Sbill */ 83595Sbill register long oxvalue; 84595Sbill register struct exp *xp; 85595Sbill register struct symtab *tunnel; 86595Sbill register struct arg *aplast; 87595Sbill 88595Sbill aplast = ap + nact - 1; 89630Shenry xp = aplast->a_xp; 90630Shenry if (lastjxxx->s_tag == JXTUNNEL){ 91630Shenry lastjxxx->s_tag = JXINACTIVE; 92630Shenry tunnel = lastjxxx->s_dest; 93630Shenry xp->e_xvalue = tunnel->s_value /*index of instruction following*/ 94595Sbill - 3 /* size of brw + word*/ 95*636Shenry + ( ( (tunnel->s_jxfear == jbrfsize) && 96630Shenry (tunnel->s_jxbump == 0))?1:0); 97595Sbill /*non bumped branch byteis only 2 back*/ 98595Sbill } 99630Shenry if (lastjxxx->s_jxbump == 0){ /*wasn't bumped, so is short form*/ 100595Sbill putins(op, ap, nact); 101595Sbill } else { 102595Sbill if (op != JBR){ /*branch reverse conditional byte over 103595Sbill branch unconditional word*/ 104630Shenry oxvalue = xp->e_xvalue; 105630Shenry xp->e_xvalue = lastjxxx->s_value; 106595Sbill putins(op^1, ap, nact); 107630Shenry xp->e_xvalue = oxvalue; 108595Sbill } 109*636Shenry putins(jxxxJUMP ? JMP : BRW, aplast, 1); 110595Sbill } 111595Sbill } 112595Sbill } /*end of ijxout*/ 113595Sbill 114595Sbill jalign(xp, sp) 115595Sbill register struct exp *xp; 116595Sbill register struct symtab *sp; 117595Sbill { 118595Sbill register int mask; 119630Shenry if (xp->e_xtype != XABS || xp->e_xvalue < 0 || xp->e_xvalue > 16) { 120595Sbill yyerror("Illegal `align' argument"); 121595Sbill return; 122595Sbill } 123595Sbill flushfield(NBPW/4); 124595Sbill if (passno == 1) { 125630Shenry sp->s_tag = JXALIGN; 126630Shenry sp->s_jxfear = (1 << xp->e_xvalue) - 1; 127630Shenry sp->s_type = dotp->e_xtype; 128630Shenry sp->s_index = dotp-usedot; 129595Sbill /* 130595Sbill * We guess that the align will take up at least one 131595Sbill * byte in the code output. We will correct for this 132595Sbill * initial high guess when we explode (bump) aligns 133595Sbill * when we fix the jxxxes. We must do this guess 134595Sbill * so that the symbol table is sorted correctly 135595Sbill * and labels declared to fall before the align 136595Sbill * really get their, instead of guessing zero size 137595Sbill * and have the label (incorrectly) fall after the jxxx. 138595Sbill * This is a quirk of our requirement that indices into 139595Sbill * the code stream point to the next byte following 140595Sbill * the logical entry in the symbol table 141595Sbill */ 142630Shenry dotp->e_xvalue += 1; 143630Shenry sp->s_value = dotp->e_xvalue; 144595Sbill njxxx++; 145595Sbill } else { 146630Shenry mask = (1 << xp->e_xvalue) - 1; 147630Shenry while (dotp->e_xvalue & mask){ 148595Sbill #ifdef UNIX 149595Sbill outb(0); 150595Sbill #endif UNIX 151595Sbill #ifdef VMS 152595Sbill *vms_obj_ptr++ = -1; 153595Sbill *vms_obj_ptr++ = 0; 154630Shenry dotp->e_xvalue += 1; 155595Sbill #endif VMS 156595Sbill } 157595Sbill } 158595Sbill } 159595Sbill 160595Sbill /* 161595Sbill * Pass 1.5, resolve jxxx instructions and .align in .text 162595Sbill */ 163595Sbill jxxxfix() 164595Sbill { 165595Sbill register struct symtab *jumpfrom; 166595Sbill struct symtab **cojumpfrom, *ubjumpfrom; 167595Sbill register struct symtab *dest; 168595Sbill register struct symtab *intdest; /*intermediate dest*/ 169595Sbill register struct symtab **cointdest, *ubintdest; 170595Sbill 171595Sbill register struct symtab *tunnel; 172595Sbill int displ,nchange; 173595Sbill int badjxalign; /*if jump across an align*/ 174595Sbill int stillactives; /*if still active jxxxes*/ 175595Sbill int segno; /*current segment number*/ 176595Sbill int topono; /*which iteration in the topo sort*/ 177595Sbill register unsigned char tag; 178595Sbill /* 179595Sbill * consider each segment in turn... 180595Sbill */ 181595Sbill for (segno = 0; segno < NLOC + NLOC; segno++){ 182595Sbill badjxalign = 0; /*done on a per segment basis*/ 183595Sbill /* 184595Sbill * Do a lazy topological sort. 185595Sbill */ 186595Sbill for (topono = 1, nchange = 1; nchange != 0; topono++){ 187595Sbill #ifdef DEBUG 188595Sbill if (debug) 189595Sbill printf("\nSegment %d, topo iteration %d\n", 190595Sbill segno, topono); 191595Sbill #endif 192595Sbill nchange = 0; 193595Sbill stillactives = 0; 194595Sbill /* 195595Sbill * We keep track of one possible tunnel location. 196595Sbill * A tunnel will eventually be an unconditional 197595Sbill * branch to the same place that another jxxx 198595Sbill * will want to branch to. We will turn a 199595Sbill * branch conditional/unconditional (word) that would 200595Sbill * have to get bumped because its destination is too 201595Sbill * far away, into a branch conditional/unconditional 202595Sbill * byte to the tunnel branch conditional/unconditional. 203595Sbill * Of course, the tunnel must branch to the same place 204595Sbill * as we want to go. 205595Sbill */ 206595Sbill tunnel = 0; /*initially, no tunnel*/ 207595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ 208630Shenry tag = jumpfrom->s_tag; 209595Sbill if (tag <= IGNOREBOUND) 210595Sbill continue; /*just an ordinary symbol*/ 211595Sbill if (tag == JXALIGN){ 212595Sbill tunnel = 0; /*avoid tunneling across a flex alocation*/ 213595Sbill continue; /*we take care of these later*/ 214595Sbill } 215*636Shenry if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/ 216595Sbill || ( tag == JXINACTIVE /*inactive bumped*/ 217630Shenry && (jumpfrom->s_jxbump != 0) 218595Sbill ) 219595Sbill ) tunnel = jumpfrom; 220595Sbill if (tag != JXACTIVE) 221595Sbill continue; 222630Shenry dest = jumpfrom->s_dest; 223630Shenry if (jumpfrom->s_index != dest->s_index){ 224595Sbill yyerror("Intersegment jxxx"); 225595Sbill continue; 226595Sbill } 227630Shenry displ = dest->s_value - jumpfrom->s_value; 228595Sbill if (displ < MINBYTE || displ > MAXBYTE) { 229595Sbill /* 230595Sbill * This is an immediate lose! 231595Sbill * 232595Sbill * We first attempt to tunnel 233595Sbill * by finding an intervening jump that 234595Sbill * has the same destination. 235595Sbill * The tunnel is always the first preceeding 236595Sbill * jxxx instruction, so the displacement 237595Sbill * to the tunnel is less than zero, and 238595Sbill * its relative position will be unaffected 239595Sbill * by future jxxx expansions. 240*636Shenry * 241*636Shenry * No tunnels if doing jumps... 242595Sbill */ 243*636Shenry if ( (!jxxxJUMP) 244*636Shenry && (jumpfrom->s_jxfear > jbrfsize) 245595Sbill && (tunnel) 246630Shenry && (tunnel->s_dest == jumpfrom->s_dest) 247630Shenry && (tunnel->s_index == jumpfrom->s_index) 248630Shenry && (tunnel->s_value - jumpfrom->s_value >= 249*636Shenry MINBYTE + jxxxfsize) 250595Sbill ) { 251595Sbill /* 252595Sbill * tunnelling is OK 253595Sbill */ 254630Shenry jumpfrom->s_dest = tunnel; 255595Sbill /* 256595Sbill * no bumping needed, this 257595Sbill * is now effectively inactive 258595Sbill * but must be remembered 259595Sbill */ 260630Shenry jumpfrom->s_tag = JXTUNNEL; 261595Sbill #ifdef DEBUG 262595Sbill if(debug) 263595Sbill printf("Tunnel from %s from line %d\n", 264630Shenry jumpfrom->s_name, lineno); 265595Sbill #endif 266595Sbill continue; 267595Sbill } else { /*tunneling not possible*/ 268595Sbill /* 269595Sbill * since this will be turned 270595Sbill * into a bumped jump, we can 271595Sbill * use the unconditional jump 272595Sbill * as a tunnel 273595Sbill */ 274595Sbill tunnel = jumpfrom; 275630Shenry jumpfrom->s_tag = JXNOTYET; 276595Sbill ++nchange; 277595Sbill continue; 278595Sbill } 279595Sbill } /*end of immediate lose*/ 280595Sbill /* 281595Sbill * Do a forward search for an intervening jxxx 282595Sbill */ 283595Sbill if (displ >= 0) { 284595Sbill SEGITERATE(segno, cojumpfrom + 1,0,cointdest, 285595Sbill intdest, ubintdest, ++){ 286630Shenry if (intdest->s_value > dest->s_value) 287595Sbill break; /* beyond destination */ 288630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 289595Sbill continue; /*frozen solid*/ 290630Shenry if (intdest->s_tag == JXALIGN){ 291630Shenry jumpfrom->s_jxoveralign = 1; 292595Sbill badjxalign++; 293595Sbill } 294595Sbill /* 295595Sbill * we assume the worst case 296595Sbill * for unfrozen jxxxxes 297595Sbill */ 298630Shenry displ += intdest->s_jxfear; 299595Sbill } 300595Sbill if (displ <= MAXBYTE){ 301595Sbill /* 302595Sbill * the worst possible conditions 303595Sbill * can't hurt us, so forget about 304595Sbill * this jump 305595Sbill */ 306630Shenry jumpfrom->s_tag = JXINACTIVE; 307595Sbill } else { 308595Sbill stillactives++; 309595Sbill } 310595Sbill } else { 311595Sbill /* 312595Sbill * backward search for intervening jxxx 313595Sbill */ 314595Sbill SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 315595Sbill intdest, ubintdest, --){ 316630Shenry if (intdest->s_value <= dest->s_value) 317595Sbill break; /* beyond destination */ 318630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 319595Sbill continue; /*frozen solid*/ 320630Shenry if (intdest->s_tag == JXALIGN){ 321630Shenry jumpfrom->s_jxoveralign = 1; 322595Sbill badjxalign++; 323595Sbill } 324630Shenry displ -= intdest->s_jxfear; 325595Sbill } 326595Sbill if (displ >= MINBYTE) { 327630Shenry jumpfrom->s_tag = JXINACTIVE; 328595Sbill } else { 329595Sbill stillactives++; 330595Sbill } 331595Sbill } /*end of backwards search*/ 332595Sbill } /*end of iterating through all symbols in this seg*/ 333595Sbill 334595Sbill if (nchange == 0) { 335595Sbill /* 336595Sbill * Now, if there are still active jxxx entries, 337595Sbill * we are partially deadlocked. We can leave 338595Sbill * these jxxx entries in their assumed short jump 339595Sbill * form, as all initial displacement calcualtions 340595Sbill * are hanging on unresolved jxxx instructions 341595Sbill * that might explode into a long form, causing 342595Sbill * other jxxxes jumping across the first set of 343595Sbill * jxxxes to explode, etc. 344595Sbill * However, if a jxxx jumps across a .align, 345595Sbill * we assume the worst for the deadlock cycle, 346595Sbill * and resolve all of them towards the long 347595Sbill * jump. 348595Sbill * Currently, the C compiler does not produce 349595Sbill * jumps across aligns, as aligns are only used 350595Sbill * in data segments, or in text segments to align 351595Sbill * functions. 352595Sbill */ 353595Sbill if (stillactives){ 354595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 355595Sbill ubjumpfrom, ++){ 356630Shenry if (jumpfrom->s_tag == JXACTIVE){ 357630Shenry jumpfrom->s_tag = 358595Sbill badjxalign?JXNOTYET:JXINACTIVE; 359595Sbill } 360595Sbill } 361595Sbill if (badjxalign){ 362595Sbill jxxxbump(segno, (struct symtab **)0); 363595Sbill } 364595Sbill } 365595Sbill /* 366595Sbill * Handle all of the .align s 367595Sbill */ 368595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 369595Sbill ubjumpfrom, ++){ 370630Shenry if (jumpfrom->s_tag == JXALIGN){ 371595Sbill /* 372595Sbill * Predict the true displacement 373595Sbill * needed, irregardless of the 374595Sbill * fact that we guessed 1 375595Sbill */ 376630Shenry displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 377595Sbill if (displ == 0){ /*no virtual displacement*/ 378630Shenry jumpfrom->s_jxfear = -1; 379595Sbill } else { 380630Shenry jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 381595Sbill /* 382630Shenry * assert jumpfrom->s_jxfear > 0 383595Sbill */ 384630Shenry if (jumpfrom->s_jxfear == 1){ 385595Sbill /*our prediction was correct*/ 386595Sbill continue; 387595Sbill } 388595Sbill /* 389630Shenry * assert jumpfrom->s_jxfear > 1 390595Sbill */ 391630Shenry jumpfrom->s_jxfear -= 1; /*correct guess*/ 392595Sbill } 393595Sbill /* 394630Shenry * assert jumpfrom->s_jxfear = -1, +1...2**n-1 395595Sbill */ 396630Shenry jumpfrom->s_tag = JXNOTYET; /*signal*/ 397595Sbill jxxxbump(segno, cojumpfrom); 398630Shenry jumpfrom->s_tag = JXINACTIVE; 399595Sbill /* 400595Sbill * Assert jxfrom->jxvalue indexes the first 401595Sbill * code byte after the added bytes, and 402595Sbill * has n low order zeroes. 403595Sbill */ 404595Sbill } 405595Sbill } /*end of walking through each segment*/ 406595Sbill } /*end of no changes */ 407595Sbill else { /*changes, and still have to try another pass*/ 408595Sbill jxxxbump(segno, (struct symtab **)0); 409595Sbill } 410595Sbill } /*end of doing the topologic sort*/ 411595Sbill } /*end of iterating through all segments*/ 412595Sbill } /*end of jxxxfix*/ 413595Sbill 414595Sbill /* 415595Sbill * Go through the symbols in a given segment number, 416595Sbill * and see which entries are jxxx entries that have 417595Sbill * been logically "exploded" (expanded), but for which 418595Sbill * the value of textually following symbols has not been 419595Sbill * increased 420595Sbill */ 421595Sbill 422595Sbill jxxxbump(segno, starthint) 423595Sbill int segno; 424595Sbill struct symtab **starthint; 425595Sbill { 426595Sbill register struct symtab **cosp, *sp; 427595Sbill register struct symtab *ub; 428595Sbill register int cum_bump; 429595Sbill register unsigned char tag; 430595Sbill 431595Sbill cum_bump = 0; 432595Sbill SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 433630Shenry tag = sp->s_tag; 434595Sbill if (tag == JXNOTYET){ 435595Sbill #ifdef DEBUG 436595Sbill if (debug){ 437630Shenry if (sp->s_dest != 0) 438595Sbill printf("Explode jump to %s on line %d\n", 439630Shenry sp->s_dest->s_name, lineno); 440595Sbill else 441595Sbill printf("Explode an align!\n"); 442595Sbill } 443595Sbill #endif 444630Shenry sp->s_tag = JXINACTIVE; 445630Shenry sp->s_jxbump = 1; 446630Shenry cum_bump += sp->s_jxfear; 447595Sbill } 448595Sbill /* 449595Sbill * Only bump labels and jxxxes. Ignored entries can 450595Sbill * be incremented, as they are thrown away later on. 451595Sbill * Stabds are given their final value in the second 452595Sbill * pass. 453595Sbill */ 454595Sbill if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 455630Shenry sp->s_value += cum_bump; 456595Sbill } 457630Shenry usedot[segno].e_xvalue += cum_bump; 458595Sbill } 459