AS AS PROGRAM as - assembler for the Motorola 68000 USAGE as [-i] [-p] [-u] [-L] [-N] sourcefile FUNCTION 'as' is the REGULUS 68000 assembler. It is used to assemble a program for the Motorola 68000. The syntax accepted is identical to the Motorola 68000 cross assembler as described in Motorola Manual M68KXASM(D3) with the exceptions and additions described below. The source file must be present as the first argument. The assembler always produces a relocatable object file whose name is the same as the source file primary name with a ".o" extension -- ie. if the source file name is "test.s" then the object file name is "test.o"; if the source file name is "pgm1" then the object file name is "pgm1.o". The -i option is used to initialize the assembler in the case that the file '/lib/as68symb' does not exist or becomes corrupted. It also requires the use of the initialization file /lib/as68init. The command would be of the form : 'as -i /lib/as68init'. If the -p flag is specified, the assembler produces a hexidecimal side-by-side listing on the standard output (you may want to redirect this to a file). Error messages are also produced on the standard output file whether or not the -p flag is specified. If the -u flag is specified, all undefined symbols in the assembly are treated as global. If the -L flag is specified, all address constants are generated as 32-bit numbers. Default is 16-bit numbers where possible. If the -N flag is specified, pass 1.5 of the assembler is not executed. This pass changes all long relative branches to short relative branches where possible. Error messages begin with an &, indicate the source line on which the error occurred and are meant to be self-explanatory. The error messages preceded by a single '&' are generated during the first pass of the assembler and those preceded by a pair '&&' are generated during the second pass of the assembler. The following are differences between this assembler and the Motorola Cross Assembler: The assembler accepts both upper and lower case characters. Labels and variables are case sensitive ('LOOP' is different from 'Loop'), but mnemonics and REGULUS Reference Manual COMMAND AS AS directives can be in either upper or lower case. Macros are implemented using the C preprocessor which is part of the c68 command (see C68(I)). Conditional assembly is also implemented using the preprocessor. Use the command "c68 -P pgm.s" to expand macros using the C preprocessor. The expanded file is left on pgm.i. All assembler directives begin with an optional character '.'. The following directives are implemented exactly as they are described in the M68KXASM(D3) manual with a dot in front of their name: .equ, .end, .dc, and .ds. All labels must terminate with a ':', unless they start in column 1. Registers may be referenced as r0 - r15, R0 - R15, D0 - D7, d0 - d7, A0 - A7, or a0-a7. Registers R8 - R15 are the same as A0 - A7. The following assembler directives are implemented just as they are described in the UNIX Assembler Reference Manual: .text, .data, .bss These three directives instruct the assembler to change the assembler base segment to the text, data, or bss segment respectively. Each assembly starts in the text segment. It is illegal to assemble instructions or data into the bss segment. Symbols may be defined and storage may be reserved using the .ds directive in the bss segment. .globl name[,name...] xdef name[,name...] xref name[,name...] These directives make the name(s) external. If they are defined in the current assembly, this statement makes these names available to other routines during a load by lo68. If these names are not defined in the current assembly, they become undefined external references and lo68 will link them to external values of the same name in other routines. Specifying the -u flag will force the assembler to make all undefined names external. .comm name,expression This directive defines a named block common area. When several routines are linked together with lo68, all block common areas with the same name are loaded at the same address. The size of this block common storage area is the largest value of the expression part of all .comm directives with the same name. No error message is produced if the areas are of REGULUS Reference Manual - 2 - COMMAND AS AS different sizes. .even If the location counter is odd, it is incremented by one so that the next instruction or data field will begin on an even memory boundary. The relocation counter may be manipulated with a statement like: *=expr Care should be exercised when using this facility. The expression may only move the relocation counter forward. The unused space is filled with zeroes in the text or data segments and is simply not assigned in the bss segment. This facility requires the assembler to not allow comment lines which begin with "*=". Comments beginning with "* =" are allowed. ASCII string constants may be enclosed in single quotes (ie. 'ABCD') or in double quotes (ie. "ac14"). The following assembler directives have also been implemented: section # This directive is used to define a base segment like the .bss, .data and .text directives discussed above. The sections can be numbered 0 to 15 inclusive. Section 14 maps to data, section 15 is bss and all the others are text sections. offset expression This directive creates a dummy storage section. No code generating instructions may occur. It is terminated by a 'section', '.data', '.bss', '.text' or '.end'. The offset table begins at the address specified in the expression. dcb Just like the dc.b command reg reglist This directive builds a register mask which can be used by the movem instruction. One or more registers can be listed in increasing order of the form : 'R?[-R?[/R?[-R?...]...]]'. Where R? can be replaced by A0-A7, D0-D7 and R0-R15. The register list might look like : A2-A4/A7/D1/D3-D5. The registers may also be designated separated by commas (eg. A1,A2,D5,D7). Conditional assembly directives can have any level of nesting. The following conditional assembler directives have been implemented: ifeq expression REGULUS Reference Manual - 3 - COMMAND AS AS ifne expression ifle expression iflt expression ifge expression ifgt expression The expression is tested against zero (with ifeq: equal, ifne: not equal, ifle: less or equal, iflt: less than, ifge: greater or equal, ifgt: greater) and if it is evaluated true then the code enclosed is assembled, otherwise the code is ignored until the matching endc is found. ifc 'string1','string2' ifnc 'string1','string2' The two strings are compared. The 'c' condition is true if they are exactly the same, the 'nc' condition is true if they do not match. endc Signifies the end of the code to be conditionally assembled. FILES /lib/as68symb /tmp/a6????A (???? is the process id number) /lib/as68init EXTRAS The following enhancements have been added to aid the assembly language programmer by making the assembly language more regular: move, add, sub mnemonics will actually generate moveq, addq, and suba instructions where possible. If a move instruction rather than a moveq instruction is desired (affecting only lower byte or word of D register), the size attribute must be explicitly coded ie. move.b or move.w. The assembler will change any move or move.l to moveq if possible. clr.x An is allowed and will actually generate a suba.x An,An instruction. add, sub, cmp with an A register source/destination are allowed and generate adda, suba, cmpa. add, and, cmp, eor, or, sub are allowed with immediate first operands and actually generate addi, andi, cmpi, eori, ori, subi instructions if the second operand is not register direct. All branch instructions generate short relative branches where possible, including forward references. Any shift instruction with no shift count specified assumes REGULUS Reference Manual - 4 - COMMAND AS AS a shift count of one; ie. "asl r1" is equivalent to "asl #1,r1". jsr instructions are changed to bsr instructions if the resulting bsr is shorter than the jsr. Several additional mnemonics have been added to the condition code instructions which map to the standard set (bt -> bra, bhs -> bhis, bnz -> bne, bze -> beq, dbhs -> dbhi, dblo -> dbcs, dbnz -> dbne, dbze -> dbeq, shs -> scc, slo -> scc, snz -> sne, sze -> seq). BUGS .set is currently implemented as a .equ. REGULUS Reference Manual - 5 - COMMAND/* Copyright 1981 Alcyon Corporation 8716 Production Ave. San Diego, Ca. 92121 */ /* pass 2 miscellaneous routines */ #include "as68.h" int p2gi(); long stlen; int stdofd 1; char tfilname[]; int ins[], rlbits[], f2mode[]; int udfct, ftudp, pline, prsp; clrea(ap) struct op *ap; { register struct op *p; p = ap; p->ea = p->len = p->xmod = p->drlc = 0; p->con = 0; p->ext = p->idx = -1; } /* * get one operand effective adddress (operand until , or EOS) * returns: * opnd[opn].ea set to effective address mode bits * opnd[opn].len set to # bytes for operand * opnd[opn].con set to constant part of ea * opnd[opn].ext set to external symbol # if any * opnd[opn].idx set to index register if any * opnd[opn].drlc set to effective address relocation mode * opnd[opn].xmod set to index register addressing mode (word or long) */ getea(opn) { register i,disp; register struct op *p; register int t; p = &opnd[opn]; disp = 0; clrea(p); if(ckitc(pitw,(int)'#')) { p->len = (modelen==1) ? 2 : modelen; p->ea = IMM; pitw++; goto dosimp; } if(ckitc(pitw,(int)'(')) { geteal1: pitw++; if((i=getrgs()) == PC) { /*pc relative*/ p->ea = 072; /*set mode & register bits*/ p->len = 2; } else { if(i != -1) /*last was some type of register*/ pitw--; /*havent used it yet*/ if((i=getareg()) < 0) { /*not a reg # next*/ if(disp || getreg()!=-1) { uerr(14); /*illegal index reg*/ return; } pitw--; goto dosimp; /*must be expression in ()*/ } p->ea = i&7; /*put in a reg #*/ } if(ckitc(pitw,(int)',')) { /*must be index reg #*/ do_ireg(p,i); return; } ckrparen(); if(i != PC) { if(!disp && ckitc(pitw,(int)'+')) { pitw++; p->ea =| INDINC; } else if(disp) { /*indirect with displacement*/ p->ea =| INDDISP; p->len = 2; } else p->ea =| INDIRECT; } ckeop(9+opn); return; } if(ckitc(pitw,(int)'-')) { /*predecrement maybe*/ pitw++; if(ckitc(pitw,(int)'(')) { /*must be*/ pitw++; if((i = getareg()) < 0) { /*not valid a reg*/ pitw =- 2; /*must be negative expr*/ goto dosimp; } p->ea = i|DECIND; ckrparen(); ckeop(9+opn); return; } pitw--; } dosimp: /*simple addr or imm expr*/ if(i=gspreg()) { t = ins[0]; if(i==PC || (i==USP && t!=MOVE)) uerr(20); if(i==SR || i==CCR) { if(t!=AND&&t!=OR&&t!=EOR&&t!=ANDI&&t!=ORI&&t!=EORI&&t!=MOVE) uerr(20); } p->idx = i; ckeop(9+opn); return; } if((i=getreg()) >= 0) { /*register direct*/ p->ea = i; if(modelen==1 && i>=AREGLO && i<=AREGHI) uerr(20); ckeop(9+opn); return; } expr(&p2gi); if(pitw < pnite) /*expr passes one token*/ pitw--; if(extflg) { p->ext = extref; extflg = 0; } p->con = ival; p->drlc = reloc; /*relocation factor*/ if(ckitc(pitw,(int)'(')) { disp++; goto geteal1; } if(!p->ea) { /*memory address*/ if(shortadr && (!ival.wd1 || ival.wd1== -1)) { /*16-bit addrs*/ p->ea = SADDR; p->len = 2; } else { p->ea = LADDR; p->len = 4; } } ckeop(9+opn); } do_ireg(p,i,opn) struct op *p; int i, opn; { pitw++; p->idx = getreg(); if(p->idx<0 || p->idx>AREGHI) uerr(14); p->len = 2; if(!ckitc(pitw,')')) { p->xmod = getrgs() - 20; if(p->xmod<0 || p->xmod>1) { uerr(34); p->xmod = 0; } } ckrparen(); ckeop(9+opn); if(i==PC) p->ea =+ 1; else p->ea =| INDINX; } /* * get an A register specification * call with: * pitw pointing to reg operand * returns: * -1 if not vaid A reg * A reg # if valid * also updates pitw if valid */ getareg() { register i; i = getreg(); if(i>=AREGLO && i<=AREGHI) { return(i&7); } else { if(i != -1) pitw--; return(-1); } } /* * get any register specification * call with : * pitw pointing at operand * returns: * register # with pitw updated * -1 if not valid register */ getreg() { register i; i = getrgs(); if(i>=0 && i<=AREGHI) return(i); else { if(i != -1) pitw--; return(-1); } } /*get any register specification*/ getrgs() { register char *i; if(pitw->itty == ITSY) { i = pitw->itop.ptrw2; /*symbol ptr*/ if(i->flags&SYER) { pitw++; return((int)i->vl1.wd2); /*register #*/ } } return(-1); } /* check for a right paren as the next char*/ /* output error msg if not found*/ ckrparen() { if(ckitc(pitw,(int)')')) /*found it*/ pitw++; else uerr(32); } /* * check intermedate text item for special character * call with: * pointer to desired item in stbuf * character to check for * returns: * 0 => no match * 1 => match */ ckitc(ckpt,cksc) char *ckpt; { if(ckpt >= pnite || ckpt->itty != ITSP || ckpt->itop.wd2 != cksc) return(0); return(1); } /* * read intermediate text for one statement * returns: * intermediate text in stbuf */ ristb() { register riix; register short *pi; register int i; do { riix = stbuf[0].itrl; pi = &stbuf[0]; for(i=0; i<(sizeof stbuf[0])/(sizeof *pi); i++) { *pi++ = doitrd(); } if(stbuf[0].itty != ITBS) { /*best be beginning of statement */ printf("it sync error itty=%x\n",stbuf[0].itty); if( stbuf[0].itty == 0) return(0); abort(); } /* get the rest of the statement it*/ riix = stbuf[0].itrl & 0377; /*unsigned byte*/ riix--; /*already got first entry*/ while(riix--) { for(i=0; i<(sizeof stbuf[0])/(sizeof *pi); i++) { *pi++ = doitrd(); } } } while(stbuf[1].itrl == -1); /* eliminated instr, read next one */ return(1); } int errno; int nitleft; /* # of shorts left in itbuf */ doitrd() { register short i; if(pitix < itbuf || pitix > &itbuf[ITBSZ]) { printf("doitrd: buffer botch pitix=%lx itbuf=%lx end=%lx\n", pitix,itbuf,&itbuf[ITBSZ]); endit(); } if(nitleft <= 0) { pitix = itbuf; if((i=read(itfn,itbuf,sizeof itbuf)) != sizeof itbuf) { putchar(0); stdofd = 2; printf("it read error i=%d errno=%o itoffset=%ld\n", i,errno,itoffset); putchar(0); abort(); } nitleft = ITBSZ; } i = *pitix; nitleft--; itoffset += sizeof *pitix; pitix++; return(i); } /* * check for end of operand * call with * error number if this is not end of operand */ ckeop(uen) { if(pitw>=pnite) /*end of all operands*/ return(1); if(!ckitc(pitw,(int)',')) { /*not end of stmt must be op,op*/ uerr(uen); return(0); } return(1); } /* output symbol table to file*/ osymt() { register char **sx1; register char *p; register i; register j; int symcmp(); stlen = 0; if(extindx) { /*output external symbols first*/ sx1 = extbl; for(i=0;iflags&(SYXR|SYIN)) continue; osyme(p); } if(prtflg) { xline = LPP; page(); /* Pop to next Page */ printf("S y m b o l T a b l e\n\n"); xline++; /* Bump Line count */ j = ((lmte-bmte)/STESIZE); /* # elements */ qsort(bmte,j,STESIZE,symcmp); /* Sort the symbols 1st */ j = 0; /* Now count symbols / line*/ for(p=bmte; p 3) { printf("\n"); page(); j = 0; } j += psyme(p); } } } symcmp(a,b) register char *a; register char *b; { return(strncmp(a,b,NAMELEN)); } /* make all undefined symbols external*/ fixunds() { register char **sx1, **sx2; /* loop thru symbol initial reference table*/ for(sx1= sirt; sx1<&sirt[SZIRT-1]; sx1 =+ 2) { if(*(sx2 = sx1+1)==0) /* this chain is empty*/ continue; /* symbols on one chain*/ sx2 = *sx2; /*first entry on this chain*/ while(1) { if(!(sx2->flags&SYDF)) { /*not defined*/ if(undflg || sx2->flags&SYGL) { /*all or globals*/ sx2->flags = sx2->flags|SYDF|SYXR; mkextidx(sx2); } } if(sx2 == *sx1) /*end of chain*/ break; sx2 = sx2->tlnk; /*next entry in chain*/ } } } /* * output symbols in a form to be read by a debugger * call with pointer to symbol table entry * prints all undefined symbols */ osyme(aosypt) struct symtab *aosypt; { register struct symtab *osypt; register char *p1; register int i; register short *ps1; osypt = aosypt; /*pointer to symbol table entry*/ if(!prtflg && !(osypt->flags&SYDF)) { /*undefined symbol*/ pudfs(osypt); /*print undefined*/ return; } stlen =+ 14; /*one more symbol out*/ /*output symbol to loader file*/ ps1 = &(osypt->name[0]); for(i=0; iflags,&lbuf); /* output symbol flags */ if(osypt->flags&SYXR) { /*external symbol*/ putw(0,&lbuf); putw(osypt->vl1.wd1,&lbuf); } else { putw(osypt->vl1.wd1,&lbuf); /*upper half symbol value*/ putw(osypt->vl1.wd2,&lbuf); /*lower symbol value*/ } } /* * print undefined symbols * call with * pointer to undefined symbol */ pudfs(udspt) struct symtab *udspt; { nerror++; if(!ftudp) { /*first time thru*/ if(xline > (LPP-10)) xline = LPP; page(); printf("\n&& UNDEFINED SYMBOLS &&\n"); xline++; ftudp++; udfct=0; /*no symbols on this line*/ } printf("%8s ",&(udspt->name[0])); if(udfct++ > 6) { printf("\n"); udfct=0; } } psyme(osypt) register struct symtab *osypt; { register char *p1; if(((osypt->flags & SYER) != 0) || (osypt->flags&SYIN)) return(0); p1 = &(osypt->name[0]); printf("%-8s ",p1); if(osypt->flags&SYXR) { printf("******** EXT "); return(1); } if(osypt->flags&SYDF) { puthex(osypt->vl1.wd1,4); puthex(osypt->vl1.wd2,4); if(osypt->flags&SYRA) /*print relocation factor*/ printf(" DATA "); else if(osypt->flags&SYRO) printf(" TEXT "); else if(osypt->flags&SYBS) printf(" BSS "); else printf(" ABS "); } else { nerror++; printf("*UNDEFINED* "); } return(1); } /* * output source and object listing * call with * 2 => print address and binary code only * 1 => object in ins[] and instr type in format * 0 => print address only */ print(pflag) { register i,j; register int *pi; if( !prtflg ) return; /*no printing desired*/ if(fchr==EOF) return; /*end of source file*/ i = instrlen; instrlen = 1; /*to print preceeding lines*/ while(plinep2absln || pflag==2) { putchar('\n'); /*end of line*/ } else { prtline(0); if(fchr==EOF) return; putchar('\n'); fchr=gchr(); pline++; } } #ifdef BLIVOT /* This was so horrible ... */ /*print one line aligning source output*/ prtline(flg) { register i; register col, blcnt; if(fchr=='*' || flg) { /*comment*/ while(fchr!=EOLC && fchr!=EOF) { putchar(fchr); fchr = gchr(); } return; } col = 1; blcnt = 0; while(1) { if(fchr==EOLC || fchr==EOF) return; if(fchr==' '&& blcnt<3) { i= (++blcnt == 3) ? 017 : 7; while(col&i) { putchar(' '); col++; } while(fchr==' ') fchr=gchr(); if(fchr==EOLC || fchr==EOF) return; } putchar(fchr); fchr=gchr(); col++; } } #else prtline(flg) /* What you see in the editor is what you get on the listing*/ { while(fchr != EOLC && fchr != EOF) { putchar(fchr); fchr = gchr(); } } #endif /* * Heading print routine */ page() { if((prtflg == 0) || (++xline < LPP)) return; printf("\014C P / M 6 8 0 0 0 A s s e m b l e r\t\t%s\t\tPage%4d\n", "Revision 02.01",++xpage); printf("Source File: %s\n\n",sfname); xline = 3; } /* buffered putchar routine*/ putchar(c) char c; { register int i; *prtchidx++ = c; if(!c || prtchidx>=&prtchars[PRTCHLEN]) { i = prtchidx - prtchars; write(stdofd,prtchars,i); prtchidx = prtchars; } } int hibytflg[4], hibytw[4]; outbyte(bv,br) { if(hibytflg[rlflg]) { outword(hibytw[rlflg]|(bv&0xff),br); hibytflg[rlflg] = 0; } else { hibytw[rlflg] = bv<<8; hibytflg[rlflg]++; } } outword(val,rb) { switch(rlflg) { case TEXT: putw(val,&lbuf); putw(rb,&tbuf); break; case DATA: putw(val,&dabuf); putw(rb,&drbuf); break; case BSS: uerr(39); break; default: rpterr("& outword: bad rlflg\n"); abort(); } } outinstr() { register i; register int *p1, *p2; i = instrlen>>1; p1 = ins; p2 = rlbits; while(i--) { outword(*p1++, *p2++); } } /* copy data bits from temporary file to loader file*/ cpdata() { myfflush(&lbuf); myfflush(&dabuf); docp(dafn,dafnc,savelc[DATA]); } /* copy text then data relocation bits from temporary file to loader file*/ cprlbits() { myfflush(&lbuf); myfflush(&drbuf); docp(trbfn, trbfnc,savelc[TEXT]); docp(drbfn, drbfnc,savelc[DATA]); } /* * copy one of the temporary files to the loader file * call with: * file descriptor of the temporary file * last char of the temporary file name * length to copy */ docp(cfn,cfnc,length) long length; { register i; register j; close(cfn); LASTCHTFN = cfnc; cfn = openfi(tfilname,0); /* while((i=read(cfn,itbuf,512)) > 0) { */ while(length > 0) { if(length > 512) j = 512; else j = length; if((i=read(cfn,itbuf,j)) != j) { printf("& Read Error On Intermediate File: %s\n", tfilname); abort(); } if(write(lfn,itbuf,i) != i) { rpterr("& Object file write error\n"); abort(); } length -= j; } } /* print one word in hex*/ puthex(v,l) { register i,j,k; j = 12; for(i=0; i>j)&017; k =+ (k >= 10) ? ('A'-10) : '0'; putchar(k); j =- 4; } } /* check for a control operand*/ controlea(ap) struct op *ap; { register i; i = ap->ea&070; if(i==INDIRECT || i==INDDISP || i==INDINX) return(1); if(i==070) { if((ap->ea&7) <= 3) return(1); } return(0); } ckcomma() { if(ckitc(pitw,',')) { /*next token a comma*/ pitw++; return(1); } return(0); } /* * generate any necessary additional words for the effective address * call with: * pins pointing to next available word in ins[] * prlb pointing to next available word in rlbits[] * argument is ptr to op structure * * returns: * appropriate words in ins[] and rlbits[] for operand * pins and prlb updated. */ doea(apea) struct op *apea; { register i,j; register struct op *p; p = apea; switch((p->ea>>3)&7) { /* ea mode bits*/ default: /*no more words*/ return; case 5: /* d(An)*/ dodisp(p); return; case 6: /* d(An,Ri)*/ dindx: if (p->con > 127L || p->con < -128L) { uerr(35); } i = (p->con.wd2&0377) | (p->idx<<12) | (p->xmod<<11); if(p->drlc != ABS) uerr(27); *pins++ = i; *prlb++ = DABS; instrlen =+ 2; return; case 7: /*xxx.W, xxx.L, or #xxx*/ switch(p->ea&7) { case 1: /* xxx.L*/ doupper(p); p->con.wd1 = 0; /*clear for dodisp check*/ case 0: /* xxx.W*/ dodisp(p); return; case 2: /*d(PC)*/ case 3: /*d(PC,Ri.X)*/ if(p->drlc != ABS) { if(p->drlc != rlflg) /*not same reloc base*/ uerr(27); p->con =- (loctr+instrlen); p->drlc = ABS; } if((p->ea&7) == 3) /*d(PC,Ri.X)*/ goto dindx; dodisp(p); return; case 4: /* #xxx*/ chkimm(p); /*check for valid length*/ if(modelen == 4) { /*instr mode is long*/ doupper(p); p->con.wd1 = 0; /*clear for dodisp check*/ } dodisp(p); return; } } } dodisp(ap) struct op *ap; { register struct op *p; p = ap; *pins++ = p->con.wd2; /*displacement*/ if(p->con.wd1 && p->con.wd1 != -1) uerr(41); /*invalid 16-bit disp*/ *prlb++ = (p->ext != -1) ? (p->ext<<3)|EXTVAR : p->drlc; instrlen =+ 2; } doupper(p) struct op *p; { *pins++ = p->con.wd1; /*upper half of long addr or constant*/ *prlb++ = LUPPER; instrlen =+ 2; } /* * build a format 1 (add, sub, and, etc) instr * call with: * register # * mode bits * ptr to operand structure for effective address */ makef1(arreg, armode, apea) struct op *apea; { register i,j; register struct op *p; p = apea; ins[0] =| (arreg<<9); /*put in reg #*/ ins[0] =| armode; /*instr mode bits*/ ins[0] =| p->ea; /*put in effective addr bits*/ doea(p); /*may be more words in ea*/ } /* generate an immediate instr*/ genimm() { ins[0] =| (f2mode[modelen] | opnd[1].ea); if(modelen == 4) { doupper(&opnd[0]); opnd[0].con.wd1 = 0; /*clear for dodisp check*/ } chkimm(&opnd[0]); /*check for valid immed length*/ dodisp(&opnd[0]); doea(&opnd[1]); } chkimm(ap) struct op *ap; { register struct op *p; p=ap; if(modelen == 2) { /*word*/ if(p->con.wd1 && p->con.wd1!=-1) uerr(42); } else if(modelen == 1) { /*byte*/ if(p->con.wd1 && p->con.wd1!=-1) uerr(43); if(p->con.wd2>255 || p->con.wd2<=-256) uerr(43); } } /* try to make a normal instr into an immediate instr*/ makeimm() { if(opnd[0].ea != IMM) return(0); if(!dataalt(&opnd[1])) return(0); if(opcpt == addptr) opcpt = addiptr; else if(opcpt == andptr) opcpt = andiptr; else if(opcpt == orptr) opcpt = oriptr; else if(opcpt == subptr) opcpt = subiptr; else if(opcpt == cmpptr) opcpt = cmpiptr; else if(opcpt == eorptr) opcpt = eoriptr; else return(0); ins[0] = opcpt->vl1.wd2; format = (opcpt->flags)&OPFF; genimm(); return(1); } ckbytea() { if(modelen==1 && !dataea(&opnd[0])) uerr(20); /*byte mod not allowed*/ } /* get a special register token (CCR, SR, or USP)*/ gspreg() { register i; i = getrgs(); if(i>AREGHI) return(i); if(i != -1) pitw--; return(0); } /* * check an operand for a special register * call with: * ptr to operand struct * special register value */ cksprg(ap,v1) struct op *ap; { if(ap->ea) return(0); if(ap->idx == v1) return(1); return(0); } /* check for operand as any special register*/ anysprg(ap) struct op *ap; { if(ap->ea) return(0); if(ap->idx>=CCR && ap->idx<=USP) return(1); return(0); } /* copy opnd 0 to opnd 1*/ cpop01() { opnd[1].ea = opnd[0].ea; opnd[1].len = opnd[0].len; opnd[1].con = opnd[0].con; opnd[1].drlc = opnd[0].drlc; opnd[1].ext = opnd[0].ext; opnd[1].idx = opnd[0].idx; opnd[1].xmod = opnd[0].xmod; } cksize(ap) /* [vlh] try to check displacement range */ struct op *ap; { long value; if ((ap->ea&070) != 070) return; value = (ap->con>0 && ap->con&0100000) ? -(ap->con&~0100000) : ap->con; if (modelen == 1) { if (value < -128L || value > 127L) /* 8 bits */ uerr(35); } else if (modelen == 2) if (value > 32767L || value < -32768L) /* 16 bits */ uerr(41); } ccr_or_sr() /* [vlh] */ { if(opnd[1].idx==CCR) modelen = 1; /*byte mode only*/ else /* [vlh] SR */ if (modelen != 2) { modelen = 2; uerr(34); } cksize(&opnd[0]); ins[0] =| IMM | f2mode[modelen]; dodisp(&opnd[0]); } get2ops() { getea(0); /*get first effective address*/ if(!ckcomma()) { uerr(10); return(1); /*no second op*/ } getea(1); /*get second effective address*/ return(0); }