/* Copyright 1983 Alcyon Corporation 8716 Production Ave. San Diego, Ca. 92121 */ char *version = "@(#)main.c 1.5 12/28/83"; /* * a two pass relocatable assembler for the Motorola 68000 microprocessor * * Bill Allen * Modified by Vicki Hutchison * * after any of this assembler is recompiled, it must be initialized * before it will execute properly. To initialize, become super user * and execute the command: * * as68 -i as68init * * where as68 is the newly compiled version of the assembler. With- * out this initialization, the assembler will not run (probably bus * error). */ #include "as68.h" #include "def.h" #ifndef DECC # include #else # include "Isignal" # define strcpy rstrcpy #endif /*sw * Define Temporary and Init file names per O/S. We use code here to * allow re-directing temp files and the init file via command line * switches. */ /************************************/ #ifdef CPM /* CPM is easy */ char *tdname = ""; /* Temp files in same directory */ char *idname = "0:"; /* Init file in user 0 */ #endif /************************************/ #ifdef WHITESM /* On whitesmith's VMS systems */ char *tdname = ""; /* Temp files in same directory */ char *idname = "bin:"; /* Init file in "bin:" */ #endif /************************************/ #ifdef UNIX /* UNIX systems are different */ char *tdname = "/tmp/"; /* Temp files in /tmp */ char *idname = "/lib/"; /* Init file in /lib */ #endif /************************************/ char tfilebase[] = {"a6AXXXXXX"}; /* Temp file basename */ char initbase[] = {"as68symb.dat"}; /* Init file basename */ /************************************/ #define INIT(op,ptr) pack(op,lmte); ptr=lemt(TRUE,oirt) main(argc,argv) int argc; char **argv; { register short i, ttmp; register long longtmp; nerror = initflg = 0; prtchidx = prtchars; if( signal(SIGINT,SIG_IGN) != SIG_IGN ) /*[mac] 4.2a*/ signal(SIGINT,rubout); if( signal(SIGQUIT,SIG_IGN) != SIG_IGN ) signal(SIGQUIT,rubout); if( signal(SIGHUP,SIG_IGN) != SIG_IGN ) signal(SIGHUP,rubout); signal(SIGTERM,rubout); pitix = itbuf; pexti = extbl; #ifndef DECC ttmp = (STESIZE*SZMT) + 2; bmte = sbrk(ttmp); longtmp = bmte; /* 11 apr 83, for vax */ if(longtmp&1L) /* 11 apr 83, for vax */ bmte++; /*make it even*/ emte = bmte + ttmp - 2; /*end of main table*/ #endif if(argc<=1) usage(); i = 1; shortadr = 0; /*long addresses...*/ while(argv[i][0] == '-') { /*may be print or initialize*/ switch(argv[i++][1]) { case 'a': /*[vlh] 4.2, short addresses only*/ shortadr = -1; break; case 'i': /*initialize the assembler*/ initflg++; break; case 'p': /*produce a listing*/ prtflg++; break; case 'u': /*make undefined symbols external*/ undflg++; break; case 'N': /*no branch optimization*/ case 'n': /*sw */ didorg++; break; case 'L': /*4.2 OBSOLETE, long addresses only*/ case 'l': /*sw */ shortadr = 0; break; case 'T': /*generating code suitable for the 68010*/ case 't': /*sw Why is this a switch? */ m68010++; break; case 'f': /*sw Redirect temp files */ tdname = argv[i++]; break; case 's': /*sw Change symbol table prefix */ idname = argv[i++]; break; default: usage(); } } if(i>=argc) usage(); sfname = argv[i]; /* Remember source filename */ ifn=openfi(argv[i],0,0); /*open source file*/ setldfn(argv[i]); /*create relocatable object file name*/ lfn=openfi(ldfn,1,1); /*open loader file*/ tfilname[0] = '\0'; /* Init for strcat */ initfnam[0] = '\0'; /* */ strcat(tfilname,tdname); /*sw Build temp file */ strcat(tfilname,tfilebase); /* names */ mktemp(tfilname); /* Make it unique */ tfilptr = &tfilname[strlen(tfilname)-1] - 6; /* Points to 'A' in name */ strcat(initfnam,idname); /* Build Symbol file */ strcat(initfnam,initbase); /* name */ #ifdef DECC if(prtflg) { /* open file for assembler listing */ setlsfn(argv[i]); stdofd = openfi(lsfn,1,0); sptr = fdopen(stdofd,"w"); } else sptr = fdopen(1,"w"); #endif itfn = gettempf(); /*get a temp file for it*/ itfnc = LASTCHTFN; /*remember last char for unlink*/ trbfn = gettempf(); /*temp for text relocation bits*/ trbfnc = LASTCHTFN; dafn = gettempf(); /*temp for data binary*/ dafnc = LASTCHTFN; drbfn = gettempf(); /*temp for data relocation bits*/ drbfnc = LASTCHTFN; #ifndef DECC ttmp = (STESIZE*SZMT) + 2; bmte = sbrk(ttmp-1); longtmp = bmte; /* 11 apr 83, for vax */ if(longtmp&1L) /* 11 apr 83, for vax */ bmte++; /*make it even*/ emte = bmte + ttmp - 2; /*end of main table*/ #endif if(initflg) { /*initializing te main table*/ lmte=bmte; /*beginning main table*/ cszmt = SZMT; /*current size of main table*/ for(i = 0; i <= SZIRT-2; i += 2) { sirt[i] = &sirt[i]; /*initialize the initial ref tables*/ sirt[i+1] = 0; oirt[i] = &oirt[i]; oirt[i+1] = 0; } /*make entries in main table for directives*/ mdemt("opd",0); /*opcode definition*/ mdemt(endstr,1); /*end statement*/ mdemt("data",2); /*dsect directive(code DATA based)*/ mdemt("text",3); /*psect directive(code TEXT based)*/ mdemt(equstr,4); /*equate*/ mdemt("set",5); /*.set - same as .equ*/ mdemt("dc",8); /*define byte*/ mdemt("globl",9); /*define global (public) symbols*/ mdemt("xdef",9); /*[vlh]define global (public) symbols*/ mdemt("xref",9); /*[vlh]define global (public) symbols*/ mdemt("comm",10); /*define external symbols*/ mdemt("bss",11); /*block storage based*/ mdemt("ds",12); /*block storage based*/ mdemt(evnstr,13); /*round pc*/ mdemt(orgstr1,14); /*[vlh] internal, *= */ mdemt(orgstr2,14); /*[vlh] org location, also *= */ mdemt("mask2",15); /*[vlh] assemble for mask2, ignore*/ mdemt("reg",16); /*[vlh] register equate*/ mdemt("dcb",17); /*[vlh] define block*/ mdemt("comline",18); /*[vlh] command line*/ mdemt("idnt",19); /*[vlh] relocateable id record, ignore*/ mdemt("offset",20); /*[vlh] define offsets*/ mdemt("section",21); /*[vlh] define sections*/ mdemt("ifeq",22); /*[vlh] ca if expr = 0*/ mdemt("ifne",23); /*[vlh] ca if expr != 0*/ mdemt("iflt",24); /*[vlh] ca if expr < 0*/ mdemt("ifle",25); /*[vlh] ca if expr <= 0*/ mdemt("ifgt",26); /*[vlh] ca if expr > 0*/ mdemt("ifge",27); /*[vlh] ca if expr >= 0*/ mdemt("endc",28); /*[vlh] end ca*/ mdemt("ifc",29); /*[vlh] ca if string compare*/ mdemt("ifnc",30); /*[vlh] ca if not string compare*/ mdemt("opt",31); /*[vlh] ignored, assemb options*/ mdemt("ttl",32); /*[vlh] ttl define, ignore*/ mdemt("page",33); /*[vlh] page define, ignore*/ } else /*not initializing*/ getsymtab(); /*read initialized main table*/ rlflg = TEXT; /*code initially TEXT based*/ inoffset = 0; /*[vlh]not in offset mode*/ loctr = 0; /*no generated code*/ ca = 0; /*[vlh]depth of conditional assembly*/ extindx = 0; /*no external symbols yet*/ p2flg = 0; /*pass 1*/ ca_true = 1; /*[vlh]true unless in side false case*/ absln = 1; sbuflen = -1; /*no source yet*/ fchr = gchr(); /*get first char*/ if(!initflg) { /*not initializing*/ INIT(orgstr2,orgptr); INIT(endstr,endptr); INIT(equstr,equptr); INIT("add",addptr); INIT("addi",addiptr); INIT("addq",addqptr); INIT("sub",subptr); INIT("subi",subiptr); INIT("subq",subqptr); INIT("cmp",cmpptr); INIT("adda",addaptr); INIT("cmpa",cmpaptr); INIT("suba",subaptr); INIT("cmpm",cmpmptr); INIT("and",andptr); INIT("andi",andiptr); INIT("or",orptr); INIT("ori",oriptr); INIT("cmpi",cmpiptr); INIT("eor",eorptr); INIT("eori",eoriptr); INIT("move",moveptr); INIT("moveq",moveqptr); INIT("exg",exgptr); INIT("jsr",jsrptr); INIT("bsr",bsrptr); INIT("nop",nopptr); INIT(evnstr,evenptr); } mloop(); } usage() { #ifndef CPM rpterr("Usage: as68 [-p] [-u] [-L] [-N] sourcefile\n"); #else rpterr("Usage: as68 [-p] [-u] [-l] [-n] [-s d:] [-f d:] sourcefile\n"); #endif endit(); } /*main loop*/ mloop() { register short i; while(fchr!=EOF) { if(absln>=brkln1) /*break for debugging the assembler*/ i=0; fcflg = 0; /*first time thru expr pass one*/ cisit(); /*create it for one statement*/ } opcpt = endptr; hend(); } #define NOCODE ((i>=0&&i<6)||i==9||i==11||i==12||i==16||(i>=20&&i<=30)) /* cond-directives, section, ds, set, equ, reg, globl, end, offset */ /*create intermediate text (it) for one statement*/ /* call with first character of statement in fchr*/ cisit() { register short *p1,*p2; register short (*dirop)(); register short i, col1; /*[vlh] col1 labels in col 1...*/ char str[NAMELEN], *l; ciss1: immed[0] = immed[1] = indir[0] = indir[1] = numcon[0] = 0; numcon[1] = numsym[0] = numsym[1] = numreg[0] = numreg[1]=0; plevel = numops = opdix = explmode = 0; cistop: col1 = 1; if(fchr==EOLC) { fchr = gchr(); goto cistop; } if(fchr==' ') { col1 = 0; igblk(); if(fchr==EOLC) /*blank line*/ goto cistop; peekc = fchr; if (fchr != EOF) fchr = ' '; /* [vlh] catch eof... */ } if(fchr==EOF) return; if(fchr=='*') { /*ignore comments*/ fchr = gchr(); if(fchr=='=') { /*relocation counter assignment*/ fchr = gchr(); /*pass the =*/ horg(); /*output constants if not bss*/ } igrst(); fcflg = 0; /*clear expr first time flag for next stmt*/ goto ciss1; } /* get the opcode and label*/ mode = 'w'; /*word mode*/ igblk(); /*ignore blanks*/ poslab = 1; gterm(TRUE); poslab = 0; if(fchr==':' || fchr=='=') { /*there is a label*/ label: col1 = 0; if(itype!=ITSY) { /*not a symbol*/ uerr(2); lbt[0] = (char)0; /*no label*/ } else { p2 = &lmte->name[0]; for(p1= &lbt[0]; p1 < &lbt[NAMELEN]; ) { *p1++ = *p2++; } if(fchr==':') fchr=gchr(); /*ignore the colons*/ } labl1: ligblk(); if(fchr == EOF) return; if(fchr == '*') { igrst(); /*comment*/ goto labl1; } gterm(TRUE); if(fchr==':' || fchr=='=') { /*another label*/ if(lbt[0]) { strcpy(tlab1,lmte,NAMELEN); /*save current label */ dlabl(); /*define the last one*/ pack(tlab1,lmte); /*restor the old lable*/ } goto label; } } else lbt[0] = 0; /*no label*/ igblk(); if(fchr == '=') goto label; if(itype==ITSP) { if(ival.loword == '=') { hequ(); return; } } if(itype!=ITSY) /*not valid opcode*/ goto cisi3; if (col1) { /* [vlh] could be a label save as is... */ l = &str; strcpy(l,lmte->name,NAMELEN); } if((opcpt=lemt(TRUE,oirt))==lmte) { /*not in opcode table*/ if (col1) { /* [vlh] it's a label... */ strcpy(lmte->name,l,NAMELEN); goto label; } cisi3: if (ca_true) /* [vlh] report error if not in CA false */ xerr(3); igrst(); return; } getmode(); /*look for .b .w or .l mode flag*/ if(opcpt->flags&OPDR) { /* its a directive*/ i = opcpt->vl1; if (!ca_true && (i < LOW_CA || i > HI_CA)) { igrst(); return; } if (inoffset) /* [vlh] */ if (!(NOCODE)) { /* can't generate code in offset */ xerr(12); return; } dirop = p1direct[i]; /*call routine to handle directive*/ (*dirop)(); return; } else if (!ca_true) { /* [vlh] */ igrst(); return; } else if (inoffset) { /* [vlh] */ xerr(12); return; } opcval = (opcpt->vl1); /*opcode*/ format = (opcpt->flags&OPFF); /*format of this instr*/ if (explmode) if (!modeok()) { xerr(16); return; } dlabl(); /*define label*/ opitb(); /*beginning of statement*/ if(format) opito(); /*may have operands*/ else igrst(); /*only comments*/ format = (opcpt->flags&OPFF); /* may have changed*/ /*end of statement*/ i = calcilen(); stbuf[1].itrl = i; /*assumed instruction length*/ stbuf[0].itrl = itwc; /*number of it entries*/ wostb(); /*write out statement buffer*/ loctr += i; } getmode() { if (fchr=='.') { fchr = gchr(); switch (fchr) { case 'b': case 'B': case 's': case 'S': modelen = BYTESIZ; mode = BYTE; break; case 'w': case 'W': modelen = WORDSIZ; mode = WORD; break; case 'l': case 'L': modelen = LONGSIZ; mode = LONG; break; default: peekc = fchr; fchr = '.'; goto getm1; } explmode++; fchr = gchr(); igblk(); return; } getm1: if(opcpt == exgptr) { /*length is long*/ modelen = LONGSIZ; mode = LONG; } else { mode = WORD; /*default is word*/ modelen = WORDSIZ; } } /* check to be sure specified mode is legal */ modeok() /* [vlh] */ { switch(format) { case 0 : case 14 : case 18 : return(FALSE); case 13 : case 15 : case 20 : case 21 : return(modelen==BYTESIZ?FALSE:TRUE); case 4 : case 25 : return(modelen==BYTESIZ?TRUE:FALSE); case 7 : case 9 : return(modelen==WORDSIZ?FALSE:TRUE); case 5 : case 11 : case 28 : return(modelen==WORDSIZ?TRUE:FALSE); case 6 : return(modelen==LONGSIZ?FALSE:TRUE); case 12 : case 30 : case 22 : case 29 : return(modelen==LONGSIZ?TRUE:FALSE); default : return(TRUE); } } /* calculate the instruction length in bytes*/ calcilen() { register short i; register long l; register char *p; i = 2; /*all instrs at least 2 bytes*/ switch(format) { case 20: i += 2; /*for reg mask*/ case 1: /*two ea's -- one of which may be a reg*/ case 15: case 30: case 26: case 5: case 3: case 21: i += lenea(1); case 16: case 24: case 25: case 29: i += lenea(0); break; case 9: /* [vlh] explicit jmp length... */ if (!explmode) i += lenea(0); else return(mode==LONG?6:4); /*[vlh] explicit jmp.? */ break; case 7: i += (immed[0]) ? 2+lenea(1) : lenea(1); break; case 14: case 11: case 19: case 31: i += 2; /*always 4 bytes*/ break; case 6: /*relative branches*/ if(itwc == ITOP1+1) { if(stbuf[ITOP1].itty == ITCN) l = stbuf[ITOP1].itop; else if(stbuf[ITOP1].itty == ITSY) { p = stbuf[ITOP1].itop.ptrw2; if(p->flags&SYDF) l = p->vl1; /*symbol value*/ else goto loffst; } else goto loffst; l -= (loctr+2); if(l<=127 && l>=-128) /*8 bit offset*/ break; } loffst: if (!explmode || modelen > BYTESIZ) /*[vlh] recognize br extensions*/ i += 2; /*long offset for branches*/ break; case 2: i += (mode==LONG?4:2) + lenea(1); break; case 23: if(immed[0]) i += (mode==LONG?4:2); case 17: case 22: i += lenea(1); break; case 8: if(numops==1) /*memory shift instruction*/ i += shiftea(0); break; } return(i); } /* calc the length of an effective address*/ lenea(lidx) int lidx; { if(immed[lidx]) return(mode==LONG?LONGSIZ:WORDSIZ); return(shiftea(lidx)); } shiftea(lidx) int lidx; { if(indir[lidx] && numreg[lidx]) return((numcon[lidx] || numsym[lidx]) ? 2 : 0); if(numsym[lidx] || numcon[lidx]) return((!shortadr || numcon[lidx]==2) ? 4 : 2); return(0); } /* *define a label if there is one to define * call with: * label name in lbt if it exists * else lbt[0] == 0 */ dlabl() { if(lbt[0]) { /*got a label*/ pack(lbt,lmte); /*put label in main table*/ lblpt=lemt(FALSE,sirt); /*look up label*/ if(lblpt != lmte) { /*symbol entered previously*/ if(lbt[0] == '~') { /*local symbol -- may be duplicate*/ lblpt = lmte; mmte(); } else { if(lblpt->flags&SYXR) { uerr(29); lblpt = 0; return; } if((lblpt->flags)&SYDF) { uerr(1); lblpt = 0; return; } } } else { mmte(); /*make label entry in main table*/ } lblpt->flags |= SYDF; /*label is now defined*/ if(rlflg == TEXT) lblpt->flags |= SYRO; else if(rlflg == DATA) lblpt->flags |= SYRA; else if(rlflg == BSS) lblpt->flags |= SYBS; /* No flags to set if absolute */ lblpt->vl1 = loctr; /*label value*/ } else lblpt = 0; } /* * output it for operands * gets intput from gterm * puts output in stbuf using itwc as an index * itwc should point at the next entry to be made in stbuf */ opito() { register short lopcomma; lopcomma = symcon = chmvq = 0; numops++; /*count first operand*/ while(1) { starmul = symcon; /*star is multiply op if flag is set*/ if(fchr=='\'' || fchr=='"') lopcomma = 0; gterm(FALSE); /*get a term*/ if(itwc==ITOP1 && format==CLRFOR && opcval==CLRVAL) chgclr(); opitoo(); /*output it for one operand*/ if(itype==ITSP && ival.loword==',') { if (plevel==1 && !numcon[opdix]) /* [vlh] */ numcon[opdix] = 1; if(lopcomma) uerr(30); lopcomma++; igblk(); /*ignore blanks for 68000 C compiler*/ } else lopcomma=0; if(ival==EOLC && itype==ITSP) /*end of operands*/ break; if(fchr==EOLC) { fchr=gchr(); break; } } if(chmvq) /*changed move to moveq*/ if(numops!=2 || immed[1] || indir[1] || numcon[1] || numsym[1] || numreg[1]>=AREGLO) { stbuf[2].itop.ptrw2 = moveptr; /*change it back*/ opcpt = moveptr; } if (stbuf[2].itop.ptrw2==cmpptr) /* [vlh] cmp -> cmpm ?? */ if (numreg[0] && numreg[1] && indir[0] && indir[1]) { stbuf[2].itop.ptrw2 = cmpmptr; opcpt = cmpmptr; } if(lopcomma) uerr(30); } /* change clr.l An to suba.l An,An*/ chgclr() { register char *p; if(itype==ITSY) { /*first op is symbol*/ p = lemt(FALSE,sirt); if(p==lmte) return; if(!(p->flags&SYER) || p->vl1= STMAX) { /*it overflow*/ rpterr("i.t. overflow\n"); abort(); } pitw->itty = itype; /*type of it entry*/ /*put symbol in it buffer*/ if(itype==ITSY) { sp=lemt(FALSE,sirt); /*look up it main table*/ pitw->itop.ptrw2 = sp; /*ptr to symbol entry*/ if(sp==lmte) /*first occurrance*/ mmte(); itwc++; /*count entries in it buffer*/ pitw++; if(!(sp->flags&SYER)) /*is it a register?*/ numsym[opdix]++; else if(sp->vl1) /*yes, a register & not D0 */ numreg[opdix] = sp->vl1; return; } else if(itype == ITCN ) { if(ival.hiword && ival.hiword != -1) numcon[opdix] = 2; else if(!numcon[opdix]) numcon[opdix] = 1; if(numops == 1) tryquick(); } /* special characters and constants*/ pitw->itop = ival; pitw->itrl = reloc; itwc++; pitw++; } /* change add into addq and sub into subq if possible*/ tryquick() { register char *p; register long l; if(fchr!=',' || !immed[0]) return; l = ival; if(itwc != ITOP1+1) { if(itwc!=ITOP1+2 || stbuf[ITOP1+1].itty!=ITSP || stbuf[ITOP1+1].itop.loword != '-') return; l = -l; } p = stbuf[2].itop.ptrw2; if(p==moveptr) { if(explmode && modelen != LONGSIZ) /*dont change .w or .b*/ return; if(l>=-128 && l<=127) { stbuf[2].itop.ptrw2 = moveqptr; opcpt = moveqptr; chmvq++; } return; } if(l<=0 || l>8) { return; } if(p==addptr || p==addiptr) { stbuf[2].itop.ptrw2 = opcpt = addqptr; } else if(p==subptr || p==subiptr) { stbuf[2].itop.ptrw2 = opcpt = subqptr; } } strcpy(astr1, astr2, alen) char *astr1, *astr2; register int alen; { register char *str1, *str2; str1 = astr1; str2 = astr2; while (--alen != -1) *str1++ = *str2++; } /* index - find the index of a character in a string*/ /* This is identical to Software Tools index.*/ index(str,chr) /* returns index of c in str or -1*/ char *str; /* pointer to string to search*/ char chr; /* character to search for*/ { register char *s; register short i; for( s = str, i = 0; *s != '\0'; i++ ) if( *s++ == chr ) return(i); return(-1); }