/* * Copyright (c) 1980 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint static char sccsid[] = "@(#)put.c 5.1 (Berkeley) 6/18/85"; #endif not lint #include "whoami.h" #include "opcode.h" #include "0.h" #include "objfmt.h" #ifdef PC # include "pc.h" # include "align.h" #else short *obufp = obuf; #endif /* * If DEBUG is defined, include the table * of the printing opcode names. */ #ifdef DEBUG #include "OPnames.h" #endif #ifdef OBJ /* * Put is responsible for the interpreter equivalent of code * generation. Since the interpreter is specifically designed * for Pascal, little work is required here. */ /*VARARGS*/ put(a) { register int *p, i; register char *cp; register short *sp; register long *lp; int n, subop, suboppr, op, oldlc; char *string; static int casewrd; /* * It would be nice to do some more * optimizations here. The work * done to collapse offsets in lval * should be done here, the IFEQ etc * relational operators could be used * etc. */ oldlc = (int) lc; /* its either this or change put to return a char * */ if ( !CGENNING ) /* * code disabled - do nothing */ return (oldlc); p = &a; n = *p++; suboppr = subop = (*p >> 8) & 0377; op = *p & 0377; string = 0; #ifdef DEBUG if ((cp = otext[op]) == NIL) { printf("op= %o\n", op); panic("put"); } #endif switch (op) { case O_ABORT: cp = "*"; break; case O_AS: switch(p[1]) { case 0: break; case 2: op = O_AS2; n = 1; break; case 4: op = O_AS4; n = 1; break; case 8: op = O_AS8; n = 1; break; default: goto pack; } # ifdef DEBUG cp = otext[op]; # endif DEBUG break; case O_FOR1U: case O_FOR2U: case O_FOR4U: case O_FOR1D: case O_FOR2D: case O_FOR4D: /* relative addressing */ p[1] -= ( unsigned ) lc + sizeof(short); /* try to pack the jump */ if (p[1] <= 127 && p[1] >= -128) { suboppr = subop = p[1]; p++; n--; } else { /* have to allow for extra displacement */ p[1] -= sizeof(short); } break; case O_CONG: case O_LVCON: case O_CON: case O_LINO: case O_NEW: case O_DISPOSE: case O_DFDISP: case O_IND: case O_OFF: case O_INX2: case O_INX4: case O_CARD: case O_ADDT: case O_SUBT: case O_MULT: case O_IN: case O_CASE1OP: case O_CASE2OP: case O_CASE4OP: case O_FRTN: case O_WRITES: case O_WRITEC: case O_WRITEF: case O_MAX: case O_MIN: case O_ARGV: case O_CTTOT: case O_INCT: case O_RANG2: case O_RSNG2: case O_RANG42: case O_RSNG42: case O_SUCC2: case O_SUCC24: case O_PRED2: case O_PRED24: if (p[1] == 0) break; case O_CON2: case O_CON24: pack: if (p[1] <= 127 && p[1] >= -128) { suboppr = subop = p[1]; p++; n--; if (op == O_CON2) { op = O_CON1; # ifdef DEBUG cp = otext[O_CON1]; # endif DEBUG } if (op == O_CON24) { op = O_CON14; # ifdef DEBUG cp = otext[O_CON14]; # endif DEBUG } } break; case O_CON8: { short *sp = (short *) (&p[1]); #ifdef DEBUG if ( opt( 'k' ) ) printf ( "%5d\tCON8\t%22.14e\n" , lc - HEADER_BYTES , * ( ( double * ) &p[1] ) ); #endif # ifdef DEC11 word(op); # else word(op << 8); # endif DEC11 for ( i = 1 ; i <= 4 ; i ++ ) word ( *sp ++ ); return ( oldlc ); } default: if (op >= O_REL2 && op <= O_REL84) { if ((i = (subop >> INDX) * 5 ) >= 30) i -= 30; else i += 2; #ifdef DEBUG string = &"IFEQ\0IFNE\0IFLT\0IFGT\0IFLE\0IFGE"[i]; #endif suboppr = 0; } break; case O_IF: case O_TRA: /***** codeline = 0; *****/ /* relative addressing */ p[1] -= ( unsigned ) lc + sizeof(short); break; case O_CONC: #ifdef DEBUG (string = "'x'")[1] = p[1]; #endif suboppr = 0; op = O_CON1; # ifdef DEBUG cp = otext[O_CON1]; # endif DEBUG subop = p[1]; goto around; case O_CONC4: #ifdef DEBUG (string = "'x'")[1] = p[1]; #endif suboppr = 0; op = O_CON14; subop = p[1]; goto around; case O_CON1: case O_CON14: suboppr = subop = p[1]; around: n--; break; case O_CASEBEG: casewrd = 0; return (oldlc); case O_CASEEND: if ((unsigned) lc & 1) { lc--; word(casewrd); } return (oldlc); case O_CASE1: #ifdef DEBUG if (opt('k')) printf("%5d\tCASE1\t%d\n" , lc - HEADER_BYTES, p[1]); #endif /* * this to build a byte size case table * saving bytes across calls in casewrd * so they can be put out by word() */ lc++; if ((unsigned) lc & 1) # ifdef DEC11 casewrd = p[1] & 0377; # else casewrd = (p[1] & 0377) << 8; # endif DEC11 else { lc -= 2; # ifdef DEC11 word(((p[1] & 0377) << 8) | casewrd); # else word((p[1] & 0377) | casewrd); # endif DEC11 } return (oldlc); case O_CASE2: #ifdef DEBUG if (opt('k')) printf("%5d\tCASE2\t%d\n" , lc - HEADER_BYTES , p[1]); #endif word(p[1]); return (oldlc); case O_PUSH: lp = (long *)&p[1]; if (*lp == 0) return (oldlc); /* and fall through */ case O_RANG4: case O_RANG24: case O_RSNG4: case O_RSNG24: case O_SUCC4: case O_PRED4: /* sub opcode optimization */ lp = (long *)&p[1]; if (*lp < 128 && *lp >= -128 && *lp != 0) { suboppr = subop = *lp; p += (sizeof(long) / sizeof(int)); n--; } goto longgen; case O_TRA4: case O_CALL: case O_FSAV: case O_GOTO: case O_NAM: case O_READE: /* absolute long addressing */ lp = (long *)&p[1]; *lp -= HEADER_BYTES; goto longgen; case O_RV1: case O_RV14: case O_RV2: case O_RV24: case O_RV4: case O_RV8: case O_RV: case O_LV: /* * positive offsets represent arguments * and must use "ap" display entry rather * than the "fp" entry */ if (p[1] >= 0) { subop++; suboppr++; } # ifdef PDP11 break; # else /* * offsets out of range of word addressing * must use long offset opcodes */ if (p[1] < SHORTADDR && p[1] >= -SHORTADDR) break; else { op += O_LRV - O_RV; # ifdef DEBUG cp = otext[op]; # endif DEBUG } /* and fall through */ # endif PDP11 case O_BEG: case O_NODUMP: case O_CON4: case O_CASE4: longgen: n = (n << 1) - 1; if ( op == O_LRV ) { n--; # if defined(ADDR32) && !defined(DEC11) p[n / 2] <<= 16; # endif } #ifdef DEBUG if (opt('k')) { printf("%5d\t%s", lc - HEADER_BYTES, cp+1); if (suboppr) printf(":%d", suboppr); for ( i = 2, lp = (long *)&p[1]; i < n ; i += sizeof ( long )/sizeof ( short ) ) printf( "\t%D " , *lp ++ ); if (i == n) { sp = (short *)lp; printf( "\t%d ", *sp ); } pchr ( '\n' ); } #endif if ( op != O_CASE4 ) # ifdef DEC11 word((op & 0377) | subop << 8); # else word(op << 8 | (subop & 0377)); # endif DEC11 for ( i = 1, sp = (short *)&p[1]; i < n; i++) word ( *sp ++ ); return ( oldlc ); } #ifdef DEBUG if (opt('k')) { printf("%5d\t%s", lc - HEADER_BYTES, cp+1); if (suboppr) printf(":%d", suboppr); if (string) printf("\t%s",string); if (n > 1) pchr('\t'); for (i=1; iclass != TYPE) ap = ap->type; if (ap->value[ NL_ELABEL ] != 0) { /* the list already exists */ return( ap -> value[ NL_ELABEL ] ); } # ifdef OBJ oldlc = (int) lc; /* same problem as put */ (void) put(2, O_TRA, lc); ap->value[ NL_ELABEL ] = (int) lc; # endif OBJ # ifdef PC putprintf(" .data", 0); aligndot(A_STRUCT); ap -> value[ NL_ELABEL ] = (int) getlab(); (void) putlab((char *) ap -> value[ NL_ELABEL ] ); # endif PC /* number of scalars */ next = ap->type; len = next->range[1]-next->range[0]+1; # ifdef OBJ (void) put(2, O_CASE2, len); # endif OBJ # ifdef PC putprintf( " .word %d" , 0 , len ); # endif PC /* offsets of each scalar name */ len = (len+1)*sizeof(short); # ifdef OBJ (void) put(2, O_CASE2, len); # endif OBJ # ifdef PC putprintf( " .word %d" , 0 , len ); # endif PC next = ap->chain; do { for(strptr = next->symbol; *strptr++; len++) continue; len++; # ifdef OBJ (void) put(2, O_CASE2, len); # endif OBJ # ifdef PC putprintf( " .word %d" , 0 , len ); # endif PC } while (next = next->chain); /* list of scalar names */ strptr = getnext(ap, &next); # ifdef OBJ do { # ifdef DEC11 w = (unsigned) *strptr; # else w = *strptr << 8; # endif DEC11 if (!*strptr++) strptr = getnext(next, &next); # ifdef DEC11 w |= *strptr << 8; # else w |= (unsigned) *strptr; # endif DEC11 if (!*strptr++) strptr = getnext(next, &next); word((int) w); } while (next); /* jump over the mess */ patch((PTR_DCL) oldlc); # endif OBJ # ifdef PC while ( next ) { while ( *strptr ) { putprintf( " .byte 0%o" , 1 , *strptr++ ); for ( w = 2 ; ( w <= 8 ) && *strptr ; w ++ ) { putprintf( ",0%o" , 1 , *strptr++ ); } putprintf( "" , 0 ); } putprintf( " .byte 0" , 0 ); strptr = getnext( next , &next ); } putprintf( " .text" , 0 ); # endif PC return( ap -> value[ NL_ELABEL ] ); } char * getnext(next, new) struct nl *next, **new; { if (next != NIL) { next = next->chain; *new = next; } if (next == NLNIL) return(""); #ifdef OBJ if (opt('k') && CGENNING ) printf("%5d\t\t\"%s\"\n", lc-HEADER_BYTES, next->symbol); #endif OBJ return(next->symbol); } #ifdef OBJ /* * Putspace puts out a table * of nothing to leave space * for the case branch table e.g. */ putspace(n) int n; { register i; if ( !CGENNING ) /* * code disabled - do nothing */ return; #ifdef DEBUG if (opt('k')) printf("%5d\t.=.+%d\n", lc - HEADER_BYTES, n); #endif for (i = even(n); i > 0; i -= 2) word(0); } putstr(sptr, padding) char *sptr; int padding; { register unsigned short w; register char *strptr = sptr; register int pad = padding; if ( !CGENNING ) /* * code disabled - do nothing */ return; #ifdef DEBUG if (opt('k')) printf("%5d\t\t\"%s\"\n", lc-HEADER_BYTES, strptr); #endif if (pad == 0) { do { # ifdef DEC11 w = (unsigned short) * strptr; # else w = (unsigned short)*strptr<<8; # endif DEC11 if (w) # ifdef DEC11 w |= *++strptr << 8; # else w |= *++strptr; # endif DEC11 word((int) w); } while (*strptr++); } else { # ifdef DEC11 do { w = (unsigned short) * strptr; if (w) { if (*++strptr) w |= *strptr << 8; else { w |= ' ' << 8; pad--; } word((int) w); } } while (*strptr++); # else do { w = (unsigned short)*strptr<<8; if (w) { if (*++strptr) w |= *strptr; else { w |= ' '; pad--; } word(w); } } while (*strptr++); # endif DEC11 while (pad > 1) { # ifdef DEC11 word(' ' | (' ' << 8)); # else word((' ' << 8) | ' '); # endif DEC11 pad -= 2; } if (pad == 1) # ifdef DEC11 word(' '); # else word(' ' << 8); # endif DEC11 else word(0); } } #endif OBJ #ifndef PC lenstr(sptr, padding) char *sptr; int padding; { register int cnt; register char *strptr = sptr; cnt = padding; do { cnt++; } while (*strptr++); return((++cnt) & ~1); } #endif /* * Patch repairs the branch * at location loc to come * to the current location. * for PC, this puts down the label * and the branch just references that label. * lets here it for two pass assemblers. */ patch(loc) PTR_DCL loc; { # ifdef OBJ patchfil(loc, (long)(lc-loc-2), 1); # endif OBJ # ifdef PC (void) putlab((char *) loc ); # endif PC } #ifdef OBJ patch4(loc) PTR_DCL loc; { patchfil(loc, (long)(lc - HEADER_BYTES), 2); } /* * Patchfil makes loc+2 have jmploc * as its contents. */ patchfil(loc, jmploc, words) PTR_DCL loc; long jmploc; int words; { register i; extern long lseek(); short val; if ( !CGENNING ) return; if (loc > (unsigned) lc) panic("patchfil"); #ifdef DEBUG if (opt('k')) printf("\tpatch %u %D\n", loc - HEADER_BYTES, jmploc); #endif val = jmploc; do { # ifndef DEC11 if (words > 1) val = jmploc >> 16; else val = jmploc; # endif DEC11 i = ((unsigned) loc + 2 - ((unsigned) lc & ~01777))/2; if (i >= 0 && i < 1024) { obuf[i] = val; } else { (void) lseek(ofil, (long) loc+2, 0); write(ofil, (char *) (&val), 2); (void) lseek(ofil, (long) 0, 2); } loc += 2; # ifdef DEC11 val = jmploc >> 16; # endif DEC11 } while (--words); } /* * Put the word o into the code */ word(o) int o; { *obufp = o; obufp++; lc += 2; if (obufp >= obuf+512) pflush(); } extern char *obj; /* * Flush the code buffer */ pflush() { register i; i = (obufp - ( ( short * ) obuf ) ) * 2; if (i != 0 && write(ofil, (char *) obuf, i) != i) perror(obj), pexit(DIED); obufp = obuf; } #endif OBJ /* * Getlab - returns the location counter. * included here for the eventual code generator. * for PC, thank you! */ char * getlab() { # ifdef OBJ return (lc); # endif OBJ # ifdef PC static long lastlabel; return ( (char *) ++lastlabel ); # endif PC } /* * Putlab - lay down a label. * for PC, just print the label name with a colon after it. */ char * putlab(l) char *l; { # ifdef PC putprintf( PREFIXFORMAT , 1 , (int) LABELPREFIX , (int) l ); putprintf( ":" , 0 ); # endif PC return (l); }