1595Sbill /* Copyright (c) 1980 Regents of the University of California */ 2*678Shenry static char sccsid[] = "@(#)asjxxx.c 4.4 08/20/80"; 3595Sbill #include <stdio.h> 4595Sbill #include "as.h" 5595Sbill #include "assyms.h" 6595Sbill 7636Shenry #define JBR 0x11 8636Shenry #define BRW 0x31 9636Shenry #define JMP 0x17 10595Sbill 11595Sbill /* 12595Sbill * The number of bytes to add if the jxxx must be "exploded" 13595Sbill * into the long form 14595Sbill */ 15636Shenry #define JBRDELTA 1 /* brb <byte> ==> brw <byte> <byte> */ 16636Shenry #define JXXXDELTA 3 /* brb <byte> ==> brb <byte> brw <byte> <byte> */ 17636Shenry #define JBRJDELTA d124 /* brb <byte> ==> jmp L^(pc) <byte>*d124 */ 18636Shenry #define JXXXJDELTA d124+2 /* brb <byte> ==> brb <byte> jmp L^(pc) <byte>*d124 */ 19595Sbill 20636Shenry int jbrfsize = JBRDELTA; 21636Shenry int jxxxfsize = JXXXDELTA; 22636Shenry 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 31636Shenry initijxxx() 32636Shenry { 33636Shenry jbrfsize = jxxxJUMP ? JBRJDELTA : JBRDELTA; 34636Shenry jxxxfsize = jxxxJUMP ? JXXXJDELTA : JXXXDELTA; 35636Shenry /* 36636Shenry * Note: ifjxxxJUMP is set, then we do NOT do any tunnelling; 37636Shenry * this was too complicated to figure out, and in the first 38636Shenry * version of the assembler, tunnelling proved to be the hardest 39636Shenry * to get to work! 40636Shenry */ 41636Shenry } 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) 64636Shenry jumpfrom->s_jxfear = jbrfsize; 65595Sbill else 66636Shenry 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*/ 95636Shenry + ( ( (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 } 109636Shenry 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; 119*678Shenry if ( (xp->e_xtype != XABS) 120*678Shenry || (xp->e_xvalue < 0) 121*678Shenry || (xp->e_xvalue > 16) 122*678Shenry ) { 123595Sbill yyerror("Illegal `align' argument"); 124595Sbill return; 125595Sbill } 126*678Shenry if ( (xp->e_xvalue > 3) 127*678Shenry && (dotp != &usedot[0]) 128*678Shenry ) { 129*678Shenry yywarning("Alignment by %d in segments other than text 0 may not work.", xp->e_xvalue); 130*678Shenry yywarning("Phase errors may occur after this .align in the second pass."); 131*678Shenry } 132595Sbill flushfield(NBPW/4); 133595Sbill if (passno == 1) { 134630Shenry sp->s_tag = JXALIGN; 135630Shenry sp->s_jxfear = (1 << xp->e_xvalue) - 1; 136630Shenry sp->s_type = dotp->e_xtype; 137630Shenry sp->s_index = dotp-usedot; 138595Sbill /* 139595Sbill * We guess that the align will take up at least one 140595Sbill * byte in the code output. We will correct for this 141595Sbill * initial high guess when we explode (bump) aligns 142595Sbill * when we fix the jxxxes. We must do this guess 143595Sbill * so that the symbol table is sorted correctly 144595Sbill * and labels declared to fall before the align 145595Sbill * really get their, instead of guessing zero size 146595Sbill * and have the label (incorrectly) fall after the jxxx. 147595Sbill * This is a quirk of our requirement that indices into 148595Sbill * the code stream point to the next byte following 149595Sbill * the logical entry in the symbol table 150595Sbill */ 151630Shenry dotp->e_xvalue += 1; 152630Shenry sp->s_value = dotp->e_xvalue; 153595Sbill njxxx++; 154595Sbill } else { 155630Shenry mask = (1 << xp->e_xvalue) - 1; 156630Shenry while (dotp->e_xvalue & mask){ 157595Sbill #ifdef UNIX 158595Sbill outb(0); 159595Sbill #endif UNIX 160595Sbill #ifdef VMS 161595Sbill *vms_obj_ptr++ = -1; 162595Sbill *vms_obj_ptr++ = 0; 163630Shenry dotp->e_xvalue += 1; 164595Sbill #endif VMS 165595Sbill } 166595Sbill } 167595Sbill } 168595Sbill 169595Sbill /* 170595Sbill * Pass 1.5, resolve jxxx instructions and .align in .text 171595Sbill */ 172595Sbill jxxxfix() 173595Sbill { 174595Sbill register struct symtab *jumpfrom; 175595Sbill struct symtab **cojumpfrom, *ubjumpfrom; 176595Sbill register struct symtab *dest; 177595Sbill register struct symtab *intdest; /*intermediate dest*/ 178595Sbill register struct symtab **cointdest, *ubintdest; 179595Sbill 180595Sbill register struct symtab *tunnel; 181595Sbill int displ,nchange; 182595Sbill int badjxalign; /*if jump across an align*/ 183595Sbill int stillactives; /*if still active jxxxes*/ 184595Sbill int segno; /*current segment number*/ 185595Sbill int topono; /*which iteration in the topo sort*/ 186595Sbill register unsigned char tag; 187595Sbill /* 188595Sbill * consider each segment in turn... 189595Sbill */ 190595Sbill for (segno = 0; segno < NLOC + NLOC; segno++){ 191595Sbill badjxalign = 0; /*done on a per segment basis*/ 192595Sbill /* 193595Sbill * Do a lazy topological sort. 194595Sbill */ 195595Sbill for (topono = 1, nchange = 1; nchange != 0; topono++){ 196595Sbill #ifdef DEBUG 197595Sbill if (debug) 198595Sbill printf("\nSegment %d, topo iteration %d\n", 199595Sbill segno, topono); 200595Sbill #endif 201595Sbill nchange = 0; 202595Sbill stillactives = 0; 203595Sbill /* 204595Sbill * We keep track of one possible tunnel location. 205595Sbill * A tunnel will eventually be an unconditional 206595Sbill * branch to the same place that another jxxx 207595Sbill * will want to branch to. We will turn a 208595Sbill * branch conditional/unconditional (word) that would 209595Sbill * have to get bumped because its destination is too 210595Sbill * far away, into a branch conditional/unconditional 211595Sbill * byte to the tunnel branch conditional/unconditional. 212595Sbill * Of course, the tunnel must branch to the same place 213595Sbill * as we want to go. 214595Sbill */ 215595Sbill tunnel = 0; /*initially, no tunnel*/ 216595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, ubjumpfrom, ++){ 217630Shenry tag = jumpfrom->s_tag; 218595Sbill if (tag <= IGNOREBOUND) 219595Sbill continue; /*just an ordinary symbol*/ 220595Sbill if (tag == JXALIGN){ 221595Sbill tunnel = 0; /*avoid tunneling across a flex alocation*/ 222595Sbill continue; /*we take care of these later*/ 223595Sbill } 224636Shenry if ( jumpfrom->s_jxfear == jbrfsize /*unconditional*/ 225595Sbill || ( tag == JXINACTIVE /*inactive bumped*/ 226630Shenry && (jumpfrom->s_jxbump != 0) 227595Sbill ) 228595Sbill ) tunnel = jumpfrom; 229595Sbill if (tag != JXACTIVE) 230595Sbill continue; 231630Shenry dest = jumpfrom->s_dest; 232630Shenry if (jumpfrom->s_index != dest->s_index){ 233595Sbill yyerror("Intersegment jxxx"); 234595Sbill continue; 235595Sbill } 236630Shenry displ = dest->s_value - jumpfrom->s_value; 237595Sbill if (displ < MINBYTE || displ > MAXBYTE) { 238595Sbill /* 239595Sbill * This is an immediate lose! 240595Sbill * 241595Sbill * We first attempt to tunnel 242595Sbill * by finding an intervening jump that 243595Sbill * has the same destination. 244595Sbill * The tunnel is always the first preceeding 245595Sbill * jxxx instruction, so the displacement 246595Sbill * to the tunnel is less than zero, and 247595Sbill * its relative position will be unaffected 248595Sbill * by future jxxx expansions. 249636Shenry * 250636Shenry * No tunnels if doing jumps... 251595Sbill */ 252636Shenry if ( (!jxxxJUMP) 253636Shenry && (jumpfrom->s_jxfear > jbrfsize) 254595Sbill && (tunnel) 255630Shenry && (tunnel->s_dest == jumpfrom->s_dest) 256630Shenry && (tunnel->s_index == jumpfrom->s_index) 257630Shenry && (tunnel->s_value - jumpfrom->s_value >= 258636Shenry MINBYTE + jxxxfsize) 259595Sbill ) { 260595Sbill /* 261595Sbill * tunnelling is OK 262595Sbill */ 263630Shenry jumpfrom->s_dest = tunnel; 264595Sbill /* 265595Sbill * no bumping needed, this 266595Sbill * is now effectively inactive 267595Sbill * but must be remembered 268595Sbill */ 269630Shenry jumpfrom->s_tag = JXTUNNEL; 270595Sbill #ifdef DEBUG 271595Sbill if(debug) 272595Sbill printf("Tunnel from %s from line %d\n", 273630Shenry jumpfrom->s_name, lineno); 274595Sbill #endif 275595Sbill continue; 276595Sbill } else { /*tunneling not possible*/ 277595Sbill /* 278595Sbill * since this will be turned 279595Sbill * into a bumped jump, we can 280595Sbill * use the unconditional jump 281595Sbill * as a tunnel 282595Sbill */ 283595Sbill tunnel = jumpfrom; 284630Shenry jumpfrom->s_tag = JXNOTYET; 285595Sbill ++nchange; 286595Sbill continue; 287595Sbill } 288595Sbill } /*end of immediate lose*/ 289595Sbill /* 290595Sbill * Do a forward search for an intervening jxxx 291595Sbill */ 292595Sbill if (displ >= 0) { 293595Sbill SEGITERATE(segno, cojumpfrom + 1,0,cointdest, 294595Sbill intdest, ubintdest, ++){ 295630Shenry if (intdest->s_value > dest->s_value) 296595Sbill break; /* beyond destination */ 297630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 298595Sbill continue; /*frozen solid*/ 299630Shenry if (intdest->s_tag == JXALIGN){ 300630Shenry jumpfrom->s_jxoveralign = 1; 301595Sbill badjxalign++; 302595Sbill } 303595Sbill /* 304595Sbill * we assume the worst case 305595Sbill * for unfrozen jxxxxes 306595Sbill */ 307630Shenry displ += intdest->s_jxfear; 308595Sbill } 309595Sbill if (displ <= MAXBYTE){ 310595Sbill /* 311595Sbill * the worst possible conditions 312595Sbill * can't hurt us, so forget about 313595Sbill * this jump 314595Sbill */ 315630Shenry jumpfrom->s_tag = JXINACTIVE; 316595Sbill } else { 317595Sbill stillactives++; 318595Sbill } 319595Sbill } else { 320595Sbill /* 321595Sbill * backward search for intervening jxxx 322595Sbill */ 323595Sbill SEGITERATE(segno, cojumpfrom - 1,1,cointdest, 324595Sbill intdest, ubintdest, --){ 325630Shenry if (intdest->s_value <= dest->s_value) 326595Sbill break; /* beyond destination */ 327630Shenry if (intdest->s_tag <= JXQUESTIONABLE) 328595Sbill continue; /*frozen solid*/ 329630Shenry if (intdest->s_tag == JXALIGN){ 330630Shenry jumpfrom->s_jxoveralign = 1; 331595Sbill badjxalign++; 332595Sbill } 333630Shenry displ -= intdest->s_jxfear; 334595Sbill } 335595Sbill if (displ >= MINBYTE) { 336630Shenry jumpfrom->s_tag = JXINACTIVE; 337595Sbill } else { 338595Sbill stillactives++; 339595Sbill } 340595Sbill } /*end of backwards search*/ 341595Sbill } /*end of iterating through all symbols in this seg*/ 342595Sbill 343595Sbill if (nchange == 0) { 344595Sbill /* 345595Sbill * Now, if there are still active jxxx entries, 346595Sbill * we are partially deadlocked. We can leave 347595Sbill * these jxxx entries in their assumed short jump 348595Sbill * form, as all initial displacement calcualtions 349595Sbill * are hanging on unresolved jxxx instructions 350595Sbill * that might explode into a long form, causing 351595Sbill * other jxxxes jumping across the first set of 352595Sbill * jxxxes to explode, etc. 353595Sbill * However, if a jxxx jumps across a .align, 354595Sbill * we assume the worst for the deadlock cycle, 355595Sbill * and resolve all of them towards the long 356595Sbill * jump. 357595Sbill * Currently, the C compiler does not produce 358595Sbill * jumps across aligns, as aligns are only used 359595Sbill * in data segments, or in text segments to align 360595Sbill * functions. 361595Sbill */ 362595Sbill if (stillactives){ 363595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 364595Sbill ubjumpfrom, ++){ 365630Shenry if (jumpfrom->s_tag == JXACTIVE){ 366630Shenry jumpfrom->s_tag = 367595Sbill badjxalign?JXNOTYET:JXINACTIVE; 368595Sbill } 369595Sbill } 370595Sbill if (badjxalign){ 371595Sbill jxxxbump(segno, (struct symtab **)0); 372595Sbill } 373595Sbill } 374595Sbill /* 375595Sbill * Handle all of the .align s 376595Sbill */ 377595Sbill SEGITERATE(segno, 0, 0, cojumpfrom, jumpfrom, 378595Sbill ubjumpfrom, ++){ 379630Shenry if (jumpfrom->s_tag == JXALIGN){ 380595Sbill /* 381595Sbill * Predict the true displacement 382595Sbill * needed, irregardless of the 383595Sbill * fact that we guessed 1 384595Sbill */ 385630Shenry displ = (jumpfrom->s_value - 1) & (unsigned)jumpfrom->s_jxfear; 386595Sbill if (displ == 0){ /*no virtual displacement*/ 387630Shenry jumpfrom->s_jxfear = -1; 388595Sbill } else { 389630Shenry jumpfrom->s_jxfear = (jumpfrom->s_jxfear + 1) - displ; 390595Sbill /* 391630Shenry * assert jumpfrom->s_jxfear > 0 392595Sbill */ 393630Shenry if (jumpfrom->s_jxfear == 1){ 394595Sbill /*our prediction was correct*/ 395595Sbill continue; 396595Sbill } 397595Sbill /* 398630Shenry * assert jumpfrom->s_jxfear > 1 399595Sbill */ 400630Shenry jumpfrom->s_jxfear -= 1; /*correct guess*/ 401595Sbill } 402595Sbill /* 403630Shenry * assert jumpfrom->s_jxfear = -1, +1...2**n-1 404595Sbill */ 405630Shenry jumpfrom->s_tag = JXNOTYET; /*signal*/ 406595Sbill jxxxbump(segno, cojumpfrom); 407630Shenry jumpfrom->s_tag = JXINACTIVE; 408595Sbill /* 409595Sbill * Assert jxfrom->jxvalue indexes the first 410595Sbill * code byte after the added bytes, and 411595Sbill * has n low order zeroes. 412595Sbill */ 413595Sbill } 414595Sbill } /*end of walking through each segment*/ 415595Sbill } /*end of no changes */ 416595Sbill else { /*changes, and still have to try another pass*/ 417595Sbill jxxxbump(segno, (struct symtab **)0); 418595Sbill } 419595Sbill } /*end of doing the topologic sort*/ 420595Sbill } /*end of iterating through all segments*/ 421595Sbill } /*end of jxxxfix*/ 422595Sbill 423595Sbill /* 424595Sbill * Go through the symbols in a given segment number, 425595Sbill * and see which entries are jxxx entries that have 426595Sbill * been logically "exploded" (expanded), but for which 427595Sbill * the value of textually following symbols has not been 428595Sbill * increased 429595Sbill */ 430595Sbill 431595Sbill jxxxbump(segno, starthint) 432595Sbill int segno; 433595Sbill struct symtab **starthint; 434595Sbill { 435595Sbill register struct symtab **cosp, *sp; 436595Sbill register struct symtab *ub; 437595Sbill register int cum_bump; 438595Sbill register unsigned char tag; 439595Sbill 440595Sbill cum_bump = 0; 441595Sbill SEGITERATE(segno, starthint, 0, cosp, sp, ub, ++){ 442630Shenry tag = sp->s_tag; 443595Sbill if (tag == JXNOTYET){ 444595Sbill #ifdef DEBUG 445595Sbill if (debug){ 446630Shenry if (sp->s_dest != 0) 447595Sbill printf("Explode jump to %s on line %d\n", 448630Shenry sp->s_dest->s_name, lineno); 449595Sbill else 450595Sbill printf("Explode an align!\n"); 451595Sbill } 452595Sbill #endif 453630Shenry sp->s_tag = JXINACTIVE; 454630Shenry sp->s_jxbump = 1; 455630Shenry cum_bump += sp->s_jxfear; 456595Sbill } 457595Sbill /* 458595Sbill * Only bump labels and jxxxes. Ignored entries can 459595Sbill * be incremented, as they are thrown away later on. 460595Sbill * Stabds are given their final value in the second 461595Sbill * pass. 462595Sbill */ 463595Sbill if (tag >= OKTOBUMP) /*only bump labels and jxxxes and floating stabs*/ 464630Shenry sp->s_value += cum_bump; 465595Sbill } 466630Shenry usedot[segno].e_xvalue += cum_bump; 467595Sbill } 468