# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # README # smalpic.c # p16c72.inc # p16c73.inc # p16c74.inc # p16c76.inc # p16c77.inc # smalpicmake # smalpicnotes # echo x - README cat >README << 'END-of-README' README The SMALpic assembler is a member of the SMAL family of assemblers modified to assemble code for Microchip's 14-bit family of PIC microcontrollers. It is moderately compatable with Microchip's assemblers, but it still has strong family connections to the SMAL family, particularly with regard to its support for macro and conditional assembly. This distribution includes: README -- this file smalpic.c -- the assembler p16c72.inc -- the include file for the PIC16C72 p16c73.inc -- the include file for the PIC16C73 p16c74.inc -- the include file for the PIC16C74 p16c76.inc -- the include file for the PIC16C76 p16c77.inc -- the include file for the PIC16C77 smalpicmake -- shell script that makes smalpic (edit to taste!) smalpicnotes -- some documentation INSTRUCTIONS see smalpicmake for how to compile and install the smalpic assembler. It should build under just about any Linux or Unix system, with no requirements other than a generic and out-of-date C compiler. END-of-README echo x - smalpic.c cat >smalpic.c << 'END-of-smalpic.c' /* smalpic.c language: C copyright 1999 by Douglas W. Jones University of Iowa Iowa City, Iowa 52242 USA Permission is granted to make copies of this program for any purpose, provided that the above copyright notice is preserved in the copy, and provided that the copy is not made for direct commercial advantage. Note: This software was developed with no outside funding. If you find it useful, and especially if you find it useful in a profit making environment, please consider making a contribution to the University of Iowa Department of Computer Science in care of: The University of Iowa Foundation Alumni Center University of Iowa Iowa City, Iowa 52242 USA */ /* the constant MAKEPATH must be provided by the command line or makefile this is the pathname of the directory containing "system" include files */ /* Simple macro assembler and linkage editor for the Microchip PIC. Started by D. W. Jones in the fall 1980 at the University of Iowa. rev 4/20/82 includes complete macro and conditional support. rev 5/5/82 includes errata and extensions. rev 2/5/84 yields 32-bit math, hex conversion. rev 12/1/88 to remove NS32000 specific code and run on Berkeley Pascal. rev 8/6/96 to translate to C with the aid of the PtoC translator. rev 7/27/97 includes command arguments. rev 6/11/98 minor bug fix in command line arguments. rev 2/28/99 conversion to the PIC. rev 7/28/00 PIC compatable IFDEF, IFNDEF. Originally coded in Hull r-mode Pascal for Prime computers: this uses 16 bit integer representations and the char type has only 64 elements. Works compatably in Hull v-mode Pascal for Prime computers: this uses 32 bit integer representations and the char type uses ASCII codes with the high bit always set to zero. Works in Prime Pascal (v-mode) when keyword 'packed' is deleted: this uses 32 bit integer representations and the char type uses ASCII codes with the high bit always set to one. Works in Berkeley Pascal, after date and time inquiry formats were changed from Hull v-mode to make this work. as modified by E. Wedel, requires 32-bit integers, but only where explicitly called for by "oversized" subrange types. as transliterated to C by D. Jones, limited to ASCII and 32 bit integers */ /* As currently configured, this program takes command line arguments to specify input, object and listing files. The .o and .l suffixes are used for object and listing files. The final suffix present on the input file name is removed before adding a .o or .l suffix; usually the input file suffix will be .a for assembly, this is not checked! The -L option suppresses listing, the -D option enables symbol table dump. The -X option enables Intel Hex output format in a .x file. */ /* This assembler is written assuming that it will run on a machine with at least 32 bit two's complement integers. */ #include #include /* boolean values */ #define true 1 #define false 0 #define boolean int /* number of symbols allowed in symboltable */ #define symsize 10000 /* opcodes and macro names allowed in optab */ #define opcodes 500 /* chars in stringpool; should be greater than the average symbol length times symsize, plus the average opcode or macro name length times opcodes, plus additional space for macro text storage, plus additional space for the macro call stack, at a minimum of 8 characters per macro nesting level, if no parameters are passed. note: poolsize must not be increased above 32767 unless appropriate changes are made to pushint and popint */ #define poolsize 30000 /* offset of null symbol in pool */ #define relsym 1 /* offset for abs symbol (just below pool */ #define abssym 0 /* pool delimiter, an illegal character in programs, presently = control-A */ #define pooldel '\001' /* replacement for virgin occurrences of -pooldel- in input stream (ha!) */ #define pdelrep '~' /* number of files in input file stack */ #define maxgetl 6 /* number of macro parameters per call. note: increasing this above 9 will require changes to onepass.getline.getmac and to onepass.macdef.getbody; these currently use decimal digits to encode parameter numbers, and must be changed to use some other scheme */ #define parmlim 8 /* one more than length of allowed input line */ #define linelen 120 /* last column of listing used for object code info note that if listcol is changed to be less than 20, the error messages must all be shortened to keep the error markup under the right places on the input line. */ #define listcol 24 /* object code items (bytes,words) listed on a line */ #define listcodes 50 /* field-size allocated to title and sub-title texts */ #define ttlbuflen 28 /* lines per page on the listing device */ #define linesdefault 56 /* characters per textual file name */ #define filelen 40 /* break character in file system path names. used for implementation of USE in hierarchic file systems. it is assumed in procedure insert that path names starting with pathbrk are absolute, while those starting with other characters are relative */ #define pathbrk '/' /* max 32-bit signed positive value 2^31-1*/ #define maxposint 2147483647L #define maxposintdiv10 214748364L /* maxposint DIV 10 (truncated) */ /* symboltable types */ /* reference to a location in the string pool */ typedef short poolref; typedef struct value { poolref base; /* symbol from which offset is relocated */ long offset; /* offset from that symbol */ } value; /* types of symbol-value associations */ enum { def, lab, /* is it a label or defined value */ intdef, /* is the value to be exported */ usedyet, /* has value been used this pass */ setyet /* has value been set this pass */ }; #define defmask (1L << ((long)def)) #define labmask (1L << ((long)lab)) #define intdefmask (1L << ((long)intdef)) #define usedyetmask (1L << ((long)usedyet)) #define setyetmask (1L << ((long)setyet)) /* symbol-value association */ typedef struct association { /* fields known only to lookup routine */ poolref id; /* fields known only by table users */ value val; long use; /* a set, one bit per type */ } association; /* opcode types */ typedef enum { operr, /* error */ /* assembler directives */ opdata, /* word constant */ opif, /* conditional assembly */ opifdf, opifndf, opelse, opendif, opint, /* internal symbol definition */ opext, /* external symbol declaration */ opcomon, /* common declaration */ opmac, opendm, opincl, /* include text from secondary source */ oporg, /* set assembly origin*/ /* PIC addition */ opres, /* advance assembly origin*/ /* PIC addition */ opconfg, /* set config word */ /* PIC addition */ opmax, /* set maxram address */ /* PIC addition */ oplist, /* listing control directive */ opnolist,/* listing control directive */ /* PIC addition */ operror, /* directive to list this line as an error msg */ opradix, /* default radix of numbers */ opttl, /* title directive */ opsbttl, /* subtitle directive */ opeject, /* page eject directive */ opend, /* end of file */ /* macro call type */ opmcall, /* macro call */ /* add machine instruction types here */ opbyteor, /* byte oriented */ opfile, /* byte oriented, file only */ opsimple, /* simple operations, no args */ opbitor, /* bit oriented */ opgen, /* general */ opgoto, /* call and goto */ } optypes; /* all textual information stored by the assembler is in the string pool */ static char strpool[poolsize - relsym + 1]; /* two data structures share the string pool: permanent text grows up from relsym, the last used location is pointed to by */ static poolref poolpos; /* transient text grows down from poolsize, organized as a stack. the format of each stack entry is documented in onepass.pushget */ /* when the stringpool fills up, it is indicated by: */ static boolean poolfull; /* some key-words are stored in the pool but not in any symbol table; these are pointed to by the following (constant) variables */ static poolref funcdf, funcfw, functy, funcab, funcrl, funcle; static poolref symset, symequ, symmac, symn; /* the assembler symbol table for labels etc */ static association symtab[symsize]; typedef short symptr; /* index type into symtab */ /* flag indicating symbol table is full */ static boolean symfull; /* the assembler symbol table for opcodes, directives, and macro names */ typedef struct _REC_optab { poolref id; optypes typ; long val, subtyp; } _REC_optab; typedef int opptr; /* index type for optab */ static _REC_optab optab[opcodes]; /* flag indicating opcode table is full */ static boolean opfull; /* textual names of input and output files */ typedef char filename[filelen]; static filename outfile, objfile, dumpfile, hexfile; static filename infile[maxgetl]; /* shallow stack of source files */ static FILE *inp[maxgetl]; /* listing output file */ static FILE *o; /* object code file */ static FILE *obj; /* hex code file */ static FILE *hex; /* object code file */ static FILE *dmp; /* input line buffer types */ typedef char linebuf[linelen]; typedef int inbufptr; /* index into a line buffer */ /* title and subtitle buffers for listing */ static linebuf titlebuf, sbttlbuf; static inbufptr titlelen, sbttllen; /* used to determine when to list title */ static long linesper; static long lineonpg; /* current page in assembly listing */ static long pagenum; /* global, set in -onepass-' routines */ static long errorcount; /* date and time buffers for listing -- see getdatetime for details */ static char datestr[16]; static char timestr[9]; /* system date/time access routines */ static void getdatetime() { char *datetime; long tloc = time(0); datetime = ctime(&tloc); /* fill datestr with "Mon Jan 16 1973", timestr with "12:00:00" */ memcpy(&(datestr[0]), &(datetime[0]), 11); memcpy(&(datestr[11]), &(datetime[20]), 4); datestr[15] = 0; memcpy(&(timestr[0]), &(datetime[11]), 8); timestr[8] = 0; } typedef char string[16]; /* inside smal32, functions simulating 32 bit two's complement machine. All of these avoid overflow or underflow; for efficiency, these may be re-implemented as external assembly language routines */ static long add(i, j) long i, j; { if (i > 0 && j > 0) { if (i <= maxposint - j) return (i + j); else return (i - maxposint + j - maxposint - 2); } else if (i < 0 && j < 0) { if (i >= -maxposint - j - 1) return (i + j); else return (i + maxposint + j + maxposint + 2); } else return (i + j); } static long neg(i) long i; { if (i == -maxposint - 1) return (-maxposint - 1); else return (-i); } static long sub(i, j) long i, j; { return (add(i, neg(j))); } static boolean ugt(i, j) long i, j; { /* unsigned greater than */ if (i >= 0) { if (j >= 0) return (i > j); else return false; } else { /* i<0 */ if (j < 0) return (i > j); else return true; } } static long mod10(i) long i; { if (i >= 0) { return (i % 10); } else { return (((i + maxposint + 1) % 10 + 8) % 10); } } static long div10(i) long i; { if (i >= 0) return (i / 10); else return ((i + maxposint + 1) / 10 + maxposintdiv10 + (mod10(i + maxposint + 1) + 8) / 10); } static long inot(i) long i; { return (add(neg(i), -1L)); } static long iand(i, j) long i, j; { return (i & j); } static long ior(i, j) long i, j; { return (i | j); } static long rightshift(i) long i; { return (i >> 1); } /* inside smal32, procedures for doing output format conversion */ static void writedec(f, v, l) FILE *f; int v, l; { /* write v as an l digit decimal number on file f */ char digits[10]; long i; long sign = ' '; if (v < 0) { v = -v; sign = '-'; } i = 0; do { digits[i] = (v % 10) + '0'; v = v / 10; i++; } while (v > 0); while ((--l) > i) { putc(' ', f); } putc(sign, f); do { i--; putc(digits[i], f); } while (i > 0); } static void writehex(f, v, l) FILE *f; long v; int l; { /* write v as an l digit hex number on file f */ char digits[8]; char digit; long i; if (l > 8) { for (i = l - 1; i >= 8; i--) putc(' ', f); l = 8; } for (i = 0; i < l; i++) { if (v < 0) { v = (v + maxposint) + 1; digit = v & 15; v = v / 16 + 134217728L; } else { digit = v & 15; v /= 16; } if (digit < 10) digits[i] = digit + '0'; else digits[i] = digit - 10 + 'A'; } for (i = l - 1; i >= 0; i--) putc(digits[i], f); } static void writesym(f, pos) FILE *f; poolref pos; { /* write the symbol from the symboltable on the indicated file */ while (strpool[pos - relsym] != pooldel) { putc(strpool[pos - relsym], f); pos++; } } static void genval(offset, base) long offset; poolref base; { /* generate value in object file based on indicated symbol with the given offset from that symbol */ if (base == abssym) { putc(' ', obj); putc('0', obj); putc('x', obj); writehex(obj, offset, 4); } else { if (offset == 0) putc(' ', obj); else { putc('0', obj); putc('x', obj); writehex(obj, offset, 4); putc('+', obj); } putc('R', obj); writesym(obj, base); } putc('\n', obj); } /* inside smal32, procedures for symbol table management */ static void clearsym() { /* initialize all entries in the symbol table to unused */ symptr i; association *WITH; /* clearsym */ symfull = false; for (i = 0; i < symsize; i++) { WITH = &symtab[i]; WITH->id = 0; WITH->use = 0; } } static void clearuse() { /* clear symbol table flags in preparation for one pass */ symptr sym; association *WITH; /* clearuse */ for (sym = 0; sym < symsize; sym++) { WITH = &symtab[sym]; WITH->use &= ~(usedyetmask | setyetmask); } } static void objsufx() { /* generate suffix to object file which defines all internal symbols */ symptr sym; association *WITH; /* objsufx */ for (sym = 0; sym < symsize; sym++) { WITH = &symtab[sym]; if ((intdefmask & WITH->use) != 0) { putc('R', obj); writesym(obj, WITH->id); putc('=', obj); genval( WITH->val.offset, WITH->val.base); } } } static poolref putpool(s) char *s; { poolref Result; int i; /* putpool */ poolpos++; Result = poolpos; for (i = 0; i <= 7; i++) { if (s[i] != ' ') { strpool[poolpos - relsym] = s[i]; poolpos++; } } strpool[poolpos - relsym] = pooldel; return Result; } static long hash(s, modulus) char *s; long modulus; { /* it is critical that this hash function match that inside onepass */ int i; long acc; /* hash */ acc = 1; for (i = 0; i <= 7; i++) { if (s[i] != ' ') { acc = (acc * 5 + s[i]) % modulus + 1; } } return acc; } static void op(s, t, v, i) char *s; optypes t; long *i; { *i = hash(s, (long)opcodes); while (optab[(*i) - 1].id != 0) { *i = ((*i) % opcodes) + 1; } optab[*i - 1].id = putpool(s); optab[*i - 1].typ = t; optab[*i - 1].val = v; optab[*i - 1].subtyp = 0; } static void opinit() { /* opinit */ /* initialize the opcode table and string pool (done only once) */ long i; for (i = 1; i <= opcodes; i++) optab[i - 1].id = 0; poolfull = false; opfull = false; poolpos = relsym; strpool[poolpos - relsym] = pooldel; /* null symbol at start of pool is default relocation base */ op("DATA ", opdata, 0L, &i); op("IF ", opif, 0L, &i); op("IFDEF ", opifdf, 0L, &i); op("IFNDEF ", opifndf, 0L, &i); op("ELSE ", opelse, 0L, &i); op("ENDIF ", opendif, 0L, &i); op("INT ", opint, 0L, &i); op("EXT ", opext, 0L, &i); op("COMMON ", opcomon, 0L, &i); op("MACRO ", opmac, 0L, &i); op("ENDM ", opendm, 0L, &i); op("INCLUDE ", opincl, 0L, &i); /* new PIC addition */ op("ORG ", oporg, 0L, &i); /* new PIC addition */ op("RES ", opres, 0L, &i); /* new PIC addition */ op("__CONFIG", opconfg, 0L, &i); /* new PIC addition */ op("__MAXRAM", opmax, 0L, &i); /* new PIC addition */ op("LIST ", oplist, 0L, &i); op("NOLIST ", opnolist, 0L, &i); /* new PIC addition */ op("ERROR ", operror, 0L, &i); op("RADIX ", opradix, 0L, &i); op("TITLE ", opttl, 0L, &i); op("SUBTITLE", opsbttl, 0L, &i); op("SUBTITL ", opsbttl, 0L, &i); op("PAGE ", opeject, 0L, &i); op("END ", opend, 0L, &i); /* machine instructions */ op("ADDWF ", opbyteor, 0x0700, &i); op("ANDWF ", opbyteor, 0x0500, &i); op("CLRF ", opfile, 0x0180, &i); op("CLRW ", opsimple, 0x0100, &i); op("COMF ", opbyteor, 0x0900, &i); op("DECF ", opbyteor, 0x0300, &i); op("DECFSZ ", opbyteor, 0x0B00, &i); op("INCF ", opbyteor, 0x0A00, &i); op("INCFSZ ", opbyteor, 0x0F00, &i); op("IORWF ", opbyteor, 0x0400, &i); op("MOVF ", opbyteor, 0x0800, &i); op("MOVWF ", opfile, 0x0080, &i); op("NOP ", opsimple, 0x0000, &i); op("RLF ", opbyteor, 0x0D00, &i); op("RRF ", opbyteor, 0x0C00, &i); op("SUBWF ", opbyteor, 0x0200, &i); op("SWAPF ", opbyteor, 0x0E00, &i); op("XORWF ", opbyteor, 0x0600, &i); op("BCF ", opbitor, 0x1000, &i); op("BSF ", opbitor, 0x1400, &i); op("BTFSC ", opbitor, 0x1800, &i); op("BTFSS ", opbitor, 0x1C00, &i); op("ADDLW ", opgen, 0x3E00, &i); op("ANDLW ", opgen, 0x3900, &i); op("CALL ", opgoto, 0x2000, &i); op("CLRWDT ", opsimple, 0x0064, &i); op("GOTO ", opgoto, 0x2800, &i); op("IORLW ", opgen, 0x3800, &i); op("MOVLW ", opgen, 0x3000, &i); op("RETFIE ", opsimple, 0x0009, &i); op("RETLW ", opgen, 0x3400, &i); op("RETURN ", opsimple, 0x0008, &i); op("SLEEP ", opsimple, 0x0063, &i); op("SUBLW ", opgen, 0x3C00, &i); op("XORLW ", opgen, 0x3A00, &i); /* note: when adding to this list, be sure to adjust the constant 'opcodes' to reflect the additions; the local procedure 'op' used above assumes that the opcode table will always have some free space. */ /* following establish unary function names.. */ funcdf = putpool("DEF "); funcfw = putpool("FWD "); functy = putpool("TYP "); funcab = putpool("ABS "); funcrl = putpool("REL "); funcle = putpool("LEN "); symset = putpool("SET "); symequ = putpool("EQU "); symmac = putpool("MACRO "); symn = putpool("N "); } /* all kinds of error messages (no more than 31 of them!) */ typedef enum { minermsg, baddig, /* bad digit in number */ baddir, /* bad assembly directive */ badrad, /* bad radix */ badrel, /* misuse of relocation in expression */ bounds, /* value out of bounds */ comexp, /* comma expected */ equexp, /* equals expected */ fwdref, /* definition must precede use */ idexp, /* identifier expected */ maxuse, /* too many source files */ baduse, /* cannot open use file */ miseif, /* missing endif */ misemc, /* missing endmac */ misquo, /* missing end quote */ muldef, /* multiple symbol definition */ mulstt, /* multiple start directives */ notfit, /* text too long for line */ notlab, /* expected label or directive */ notval, /* expected a value, got something else */ parexp, /* not a parenthesized list */ parovf, /* too many macro parameters */ phase, /* phase error in label value between passes */ quoexp, /* quoted string expected */ unbal, /* unbalanced parens */ undef, /* undefined symbol */ unfunc, /* bad function */ erropr, /* error operation */ unproc, /* unprocessed data at end of line */ maxermsg } ermsg; static char * errormsgs[] = { "---", /* 12345678901234567890123456 all error messages are 26 chars long */ "bad digit in number ", "invalid directive ", "bad radix ", "misuse of relocation ", "value out of bounds ", "comma expected ", "equals sign expected ", "name used before defined ", "symbolic name expected ", "too many include levels ", "cannot open include file ", "missing endif ", "missing endmac ", "missing end quote ", "multiple label definition ", "multiple start directives ", "text too long for line ", "not a label or directive ", "bad value or expression ", "not a parenthesized list ", "too many macro parameters ", "label differed in pass 1 ", "quoted string expected ", "unbalanced parentheses ", "undefined symbol ", "invalid function ", "error message ", "comment or eol expected ", "+++" }; /* types having to do with lexical analysis */ typedef enum { id, /* identifier */ num, /* number (hex or decimal) */ quote, /* quoted string */ colon, /* : */ dot, /* $ */ comma, /* , */ eq, /* = */ gt, /* > */ lt, /* < */ plus, /* + */ minus, /* - */ compsy, /* ~ */ notsym, /* ! */ andsym, /* & */ orsym, /* | */ bpar, /* ( */ epar, /* ) */ eol, /* end of line and start of comment */ junk /* string of unclassified characters */ } lextypes; typedef struct lexeme { /* start, end of lexeme in line */ inbufptr pos; inbufptr lim; lextypes typ; union { /* value of number */ long val; } UU; } lexeme; typedef int parm; /* static variables used within onepass and affiliated code: */ static boolean firstpass; /* true on the first pass only */ static boolean allowlist; /* true on the final pass only */ static boolean permitlisting; /* is a listing file to be opened */ static boolean makehexfile; /* format output in Intel INHX8M format */ static boolean symtabdump; /* is a symboltable dump to be created */ char charclass[256]; /* used to classify characters */ /* bits set in charclass to classify characters */ #define isvalid 1 #define ispunc 2 #define isquote 4 #define isdigit 8 #define isupper 16 #define islower 32 #define isalpha (isupper | islower) #define isalphanum (isalpha | isdigit) static void classchar( s, c ) char* s; char c; { /* in charclass, classify all chars in s as c */ char ch; while ((ch = *s) != 0) { charclass[ch] |= c; s++; } } static value loc; /* current assembly location counter */ static value objloc; /* current object code generation location counter */ static long lineno; /* current line in assembly source */ static long maxram; /* max RAM (PIC only) */ static long config; /* config word (PIC only) */ static long radix; /* current radix (PIC only) */ static lexeme lex; /* current lexeme */ static lexeme next; /* next lexeme for lookahead use */ /* variables associated with stack on transient end of stringpool */ static poolref poolsp; /* pool stack pointer */ static poolref oldsp; /* pointer to previous frame in stack */ static int actcnt; /* count of actual params in current frame */ static poolref actparm[parmlim]; /* pointers to ap's in frame */ /* variables controlling source of input */ static poolref gettext; /* loc in pool from which macro text comes */ static int getlevel; /* file from which non-macro text comes */ static linebuf line; /* line buffers and lexical analysis */ static int pos; /* current input line position */ static int ch; /* line[pos] */ static inbufptr length; /* current input line length */ /* record of errors on the current line */ static linebuf erbuf; /* markup under error */ static inbufptr ermax; /* max used position in erbuf */ static long erset; /* set of messages to generate */ /* record of code generated by current line */ typedef struct _REC_codebuf { value val; int form; } _REC_codebuf; static _REC_codebuf codebuf[listcodes]; static int codelen; /* the number of object code chunks not yet listed */ static value codeloc; /* the location counter of the first object output */ /* listing control variables */ static boolean listing; /* set to (listlevel > 0) and (allowlist) */ static long listlevel; /* dec on macro call, inc on return */ /* info about last expression */ static value expr; /* value of expression */ static boolean exprdef; /* is the value of the expression defined */ static boolean exprundef; /* does expr. contain fwd ref(s)? */ static inbufptr exprpos, exprlim; /* position of expression on line */ /* info about opcode decoded on current line */ static optypes optype; static long opval, opsubt; static inbufptr oppos, oplim; /* routines to manage stack in stringpool, these routines assume that ord(maxch)>=32; if ord(maxch)>32, they may be recoded for greater efficiency without any effect on their users */ static void pushchar(ch) char ch; { /* push one char onto stack in stringpool */ if (poolsp > poolpos) { strpool[poolsp - relsym] = ch; poolsp--; } else { poolfull = true; } } static poolref pushtext(pos, lim) inbufptr pos, lim; { /* push the indicated text onto the stack from the line, as a terminated string, return a reference to the first char */ inbufptr i; /* pushtext */ pushchar(pooldel); for (i = lim - 2; i >= pos - 1; i--) pushchar(line[i]); return (poolsp + 1); } static poolref pushitxt(i) long i; { /* push the indicated integer as a hex text string, terminated with a pooldel, and return a reference to the first char */ pushchar(pooldel); if (i == 0) { pushchar('0'); return (poolsp + 1); } else { while (i != 0) { int j = i & 0xF; if (j < 10) { pushchar((char)(j + '0')); } else { pushchar((char)((j - 10) + 'A')); } i = ((unsigned long) i) >> 4; } pushchar('x'); pushchar('0'); } } static char popchar() { /* pop one char from stack in stringpool */ poolsp++; return (strpool[poolsp - relsym]); } static void pushint(i) long i; { /* push an integer onto stack as a sequence of chars */ pushchar((char)(i & 31)); pushchar((char)((i / 32) & 31)); pushchar((char)(i / 1024)); } static long popint() { /* pop an integer from the stack as a sequence of chars */ long i; i = popchar() * 1024; i += popchar() * 32; return (i + popchar()); } static void pushget() { /* push a macro expansion control block on the stack */ int i; listlevel--; for (i = 0; i < actcnt; i++) pushint((long)actparm[i]); pushchar(actcnt); pushint((long)oldsp); pushint((long)gettext); pushchar(getlevel); oldsp = poolsp; } static void popget() { /* pop a macro expansion control block from the stack */ int i; if (poolfull) { /* can't pop safely, so go all the way */ listlevel = 1; gettext = 0; getlevel = 0; return; } /* can pop one level safely */ listlevel++; poolsp = oldsp; getlevel = popchar(); gettext = popint(); oldsp = popint(); actcnt = popchar(); for (i = actcnt - 1; i >= 0; i--) actparm[i] = popint(); } /* inside smal32.onepass, input/output routines */ static void errmsg(msg, pos, lim) ermsg msg; inbufptr pos, lim; { /* record error and position of error in line for later listing */ inbufptr i; erset |= 1L << ((long)msg); if (allowlist) { errorcount++; /* for posterity's sake */ listing = allowlist; /* force error line to be listed */ for (i = ermax; i <= pos - 2; i++) erbuf[i] = ' '; for (i = pos - 1; i <= lim - 2; i++) erbuf[i] = '='; if (lim > ermax + 1) ermax = lim - 1; } } /* routines used by getline */ static void makeend() { /* put an end directive on the line as result of end file */ /* makeend */ line[0] = 'E'; line[1] = 'N'; line[2] = 'D'; length = 3; line[3] = ';'; /* char beyond end must be initialized */ } static void getmac() { /* get one line of text from the string pool copy of macro body */ long parmnum; poolref _parm; int i; char ch; i = 0; do { /* copy literal text from pool to line */ ch = strpool[gettext - relsym]; gettext++; while (ch != pooldel && i < linelen - 1) { i++; line[i - 1] = ch; ch = strpool[gettext - relsym]; gettext++; } if (ch != pooldel) { /* isn't space in the line */ errmsg(notfit, 0, 0); while (strpool[gettext - relsym] != pooldel) gettext++; gettext++; } ch = strpool[gettext - relsym]; /* char after pooldel */ gettext++; if (charclass[ch] & isdigit) { /* macro param */ parmnum = ch - '0'; if (parmnum <= actcnt) { /* param exists */ _parm = actparm[parmnum - 1]; if (_parm > 0) { /* param is nonblank */ ch = strpool[_parm - relsym]; while (ch != pooldel && i < linelen - 1) { /* loop copying text of parameter */ i++; line[i - 1] = ch; _parm++; ch = strpool[_parm - relsym]; } if (ch != pooldel) errmsg(notfit, 0, 0); } } ch = ' '; /* force loop to continue */ } } while ((ch != pooldel) && (ch != ',')); if (ch == pooldel) { makeend(); } else { length = i; line[i] = ';'; /* this char must be initialized */ } } static void get(f) FILE *f; { /* read one line from appropriate input file */ int i; int ch; i = 0; for (;;) { ch = getc(f); if ((ch == EOF) || (ch == '\n')) break; if (i >= (linelen - 1)) break; if (ch == pooldel) ch = pdelrep; if (ch == '\t') { do { line[i] = ' '; i++; } while (((i & 7) != 0) && (i < (linelen - 1))); } else { line[i] = ch; i++; } } if (i >= (linelen - 1)) errmsg(notfit, 0, 0); if ((ch == EOF) & (i == 0)) { makeend(); } else { length = i; line[i] = ';'; /* this char must be initialized */ } } static void getline() { /* read one line from the input file, initialize the lexical analysis and listing control variables */ erset = 0; ermax = 0; if (gettext > 0) { getmac(); } else { /* lines are only counted at the bottom level! */ if (getlevel == 1) lineno++; get(inp[getlevel - 1]); } pos = 1; lex.typ = eol; lex.pos = 1; lex.lim = 1; next.typ = eol; next.pos = 1; next.lim = 1; } static void settitle(buf, len, pos, lim) char *buf; inbufptr *len, pos, lim; { /* fill the indicated title buffer with the indicated part of the input line */ inbufptr i; *len = 0; if (lim - pos > ttlbuflen - 3) lim = pos + ttlbuflen - 3; for (i = pos - 1; i < lim; i++) { (*len)++; buf[*len - 1] = line[i]; } } static void newpage() { /* force listing to the start of a new page */ inbufptr i; if (!permitlisting) return; if (lineonpg <= 1) return; putc('\f', o); /* formfeed character */ /* note that instead of using a formfeed, this routine could be written to simply output blank lines and count them with lineonpg until the count was high enough to push the listing to a new page */ lineonpg = 1; pagenum++; /* write title to listing file */ fputs("SMAL32, rev 7/00. ", o); for (i = 0; i < titlelen; i++) putc(titlebuf[i], o); for (i = titlelen; i <= ttlbuflen; i++) putc(' ', o); fputs(timestr, o); fputs(" Page ", o); writedec(o, pagenum, 1); putc('\n', o); /* linefeed character */ fputs(" ", o); for (i = 0; i < sbttllen; i++) putc(sbttlbuf[i], o); for (i = sbttllen; i <= ttlbuflen; i++) putc(' ', o); fputs( datestr, o ); putc('\n', o); /* linefeed character */ putc('\n', o); } static void listline() { /* list one line, including generated code. if there are any errors, list the error messages */ inbufptr i; ermsg msg; int col; int nextcol = 0; /* column on output listing */ int codepos; /* more permanent buffer ptr */ if (!permitlisting) return; lineonpg++; if (lineonpg >= linesper) newpage(); col = 1; codepos = codelen + 1; /* in case we don't make any code.. */ if (codelen > 0) { /* list generated code */ if (codeloc.base == abssym) putc(' ', o); else putc('+', o); writehex(o, codeloc.offset, 4L); putc(':', o); col = 7; i = 0; while (i < codelen) { /* list each code item */ _REC_codebuf *WITH; long width; i++; WITH = &codebuf[i - 1]; width = 4; nextcol = col + width + 2; if (nextcol > (listcol + 1)) { codepos = i; i = codelen; } else { if (WITH->val.base != abssym) putc('+', o); else putc(' ', o); writehex(o, WITH->val.offset, width); putc(' ', o); col = nextcol; } } } for (; col <= listcol; col++) putc(' ', o); writedec(o, lineno, 6); /* text starts in column listcol + 1 */ fputs(" ", o); for (i = 0; i < length; i++) putc(line[i], o); /* check for extended code listing */ /* list ALL generated code */ while (codepos <= codelen) { _REC_codebuf *WITH = &codebuf[codepos - 1]; long width = WITH->form * 2; nextcol += (width + 2); if (nextcol > (listcol+1)) { putc('\n', o); lineonpg++; if (lineonpg > linesper) newpage(); fputs(" ", o); nextcol = 9 + width + 2; } if (WITH->val.base != abssym) putc('+', o); else putc(' ', o); writehex(o, WITH->val.offset, width); putc(' ', o); codepos++; } codelen = 0; /* reset record of listed code */ /* write out all accumulated error messages */ if (erset != 0) { /* if */ for (msg = minermsg; (long)msg <= (long)maxermsg; msg++) { if (((1L << ((long)msg)) & erset) != 0) { /* put message into listing */ putc('\n', o); lineonpg++; if (lineonpg > linesper) newpage(); fputs( errormsgs[ msg ], o ); for (col = 26; col <= listcol + 7; col++) putc(' ', o); for (i = 0; i < ermax; i++) putc(erbuf[i], o); ermax = 0; /* put message to stderr also */ writedec(stderr, lineno, 6); fputs(" ", stderr); fputs(errormsgs[ msg ], stderr); { int l = length; if ((l + 26) > 79) l = 79 - 26; for (i = 0; i < l; i++) { putc(line[i], stderr); } } putc('\n', stderr); } } } putc('\n', o); } static void putobj(form, offset, base) int form; long offset; poolref base; { /* store value (offset,base) in current loc. (base=abssym is used for absolute values; typically, relocatable values will come from loc.base and loc.offset or expr.base and expr.offset.) use format form (1 word), save information for listing */ if (allowlist) { /* added later, generate Intel Hex file if requested */ if (makehexfile) { /* output in Intel Hex format */ int cksum = 2; int lo = (offset ) & 0xFF; int hi = (offset >> 8) & 0x3F; int addr = (loc.offset << 1) & 0xFFFF; /* sanity checks */ if ((loc.base != abssym) || (base != abssym)) { errmsg(badrel, 0, 0); } /* hex output */ putc(':', hex); fputs("02",hex); /* 2 bytes data (1 word) */ writehex(hex, addr, 4); /* byte address */ fputs("00",hex); /* type 0 is data */ writehex(hex, lo, 2); /* low byte first */ writehex(hex, hi, 2); /* high byte second */ cksum = -( 2 + + (addr >> 8) + (addr & 0xFF) + 0 + lo + hi ); writehex(hex, cksum, 2); /* windup with checksum */ putc('\n', hex); } /* first assure that code gets loaded in right loc */ if (objloc.offset != loc.offset || objloc.base != loc.base) { objloc = loc; fputs(" ORG", obj); genval( loc.offset, loc.base); } /* save appropriate listing data */ if (codelen == 0) codeloc = loc; if (codelen < listcodes) { codelen++; codebuf[codelen - 1].val.offset = offset; codebuf[codelen - 1].val.base = base; codebuf[codelen - 1].form = form; } /* then generate correct object code */ switch (form) { case 1: fputs(" DATA", obj); break; } genval( offset, base); objloc.offset = add(objloc.offset, form); } loc.offset = add(loc.offset, form); } /* procedures used only by nextlex */ static long number(radix) long radix; { long acch,accl; /* accumulates the value */ long digit; /* the value of one digit */ /* assume initially that ch is a valid digit */ acch = 0; accl = 0; do { if (charclass[ch] & isdigit) { digit = ch - '0'; } else if (ch == 'x') { digit = 0; /* very special case for PIC */ } else if (charclass[ch] & isupper) { digit = (ch - 'A') + 10; } else if (charclass[ch] & islower) { digit = (ch - 'a') + 10; } else { digit = -1; /* signal end of number */ } if (digit >= radix) { acch = 65536L; } else if (digit >= 0) { pos++; ch = line[pos - 1]; accl = accl * radix + digit; acch = acch * radix + accl / 65536L; accl %= 65536L; } } while ( (charclass[ch] & isalphanum) && (acch < 65536L) && (digit >= 0) ); if (digit >= radix) { errmsg(baddig, pos, pos + 1); while (charclass[ch] & isalphanum) { pos++; ch = line[pos - 1]; } return 0; } else if (acch >= 65536L) { while (charclass[ch] & isalphanum) { pos++; ch = line[pos - 1]; } errmsg(bounds, next.pos, pos); return 0; } else if (acch >= 32768L) return ((acch - 32768L) * 65536L - maxposint + accl - 1); else return (acch * 65536L + accl); } /* inside smal32.onepass, lexical analysis routines */ static void nextlex() { /* save the next lexeme information in the current lexeme variable, then read a new next one from the input line */ lex = next; while (line[pos - 1] == ' ') pos++; ch = line[pos - 1]; next.pos = pos; if (ch == ';') next.typ = eol; else if (charclass[ch] & ispunc) { switch (ch) { /* case */ case ':': next.typ = colon; break; case '$': next.typ = dot; break; case ',': next.typ = comma; break; case '=': next.typ = eq; break; case '>': next.typ = gt; break; case '<': next.typ = lt; break; case '+': next.typ = plus; break; case '-': next.typ = minus; break; case '~': next.typ = compsy; break; case '!': next.typ = notsym; break; case '&': next.typ = andsym; break; case '|': next.typ = orsym; break; case '(': next.typ = bpar; break; case ')': next.typ = epar; break; } pos++; } else if ((ch == '0') && (line[pos] == 'x')) { /* OxFFFF format */ next.typ = num; pos++; /* skip 0 */ pos++; /* skip x */ ch = line[pos - 1]; next.UU.val = number(16L); } else if ((ch == 'H') && (line[pos] == '\'')) { /* H'999' format */ next.typ = num; pos++; pos++; ch = line[pos - 1]; next.UU.val = number(16L); if (ch == '\'') { pos++; ch = line[pos - 1]; } else { errmsg(misquo, next.pos, next.pos + 1); } } else if ((ch == 'D') && (line[pos] == '\'')) { /* D'999' format */ next.typ = num; pos++; pos++; ch = line[pos - 1]; next.UU.val = number(10L); if (ch == '\'') { pos++; ch = line[pos - 1]; } else { errmsg(misquo, next.pos, next.pos + 1); } } else if ((ch == 'O') && (line[pos] == '\'')) { /* O'999' format */ next.typ = num; pos++; pos++; ch = line[pos - 1]; next.UU.val = number(8L); if (ch == '\'') { pos++; ch = line[pos - 1]; } else { errmsg(misquo, next.pos, next.pos + 1); } } else if ((ch == 'B') && (line[pos] == '\'')) { /* B'999' format */ next.typ = num; pos++; pos++; ch = line[pos - 1]; next.UU.val = number(2L); if (ch == '\'') { pos++; ch = line[pos - 1]; } else { errmsg(misquo, next.pos, next.pos + 1); } } else if ((ch == 'A') && (line[pos] == '\'')) { /* A'X' format */ next.typ = num; pos++; pos++; ch = line[pos - 1]; next.UU.val = ch; pos++; ch = line[pos - 1]; if (ch == '\'') { pos++; ch = line[pos - 1]; } else { errmsg(misquo, next.pos, next.pos + 1); } } else if (charclass[ch] & isdigit) { next.typ = num; next.UU.val = number(radix); } else if (charclass[ch] & isalpha) { next.typ = id; do { pos++; ch = line[pos - 1]; } while (charclass[ch] & isalphanum); } else if (ch == '#') { pos++; ch = line[pos - 1]; if (charclass[ch] & isalphanum) { next.typ = num; next.UU.val = number(16L); } else /* if */ next.typ = junk; } else if (charclass[ch] & isquote) { char mark = ch; next.typ = quote; do { pos++; } while (line[pos - 1] != mark && pos <= length); if (pos <= length) pos++; else errmsg(misquo, next.pos, next.pos + 1); } else { do { pos++; ch = line[pos - 1]; } while ((charclass[ch] & isvalid) == 0); next.typ = junk; } next.lim = pos; /* invalid lexeme */ } static void startup() { /* setup for processing one line of input */ getline(); /* read input line */ nextlex(); /* read first lexeme */ nextlex(); /* read second lexeme (allow lookahead) */ /* start parsing by looking for valid start of line */ while ( (lex.typ != id) && (lex.typ != eol) && (lex.typ != dot) ) { errmsg(notlab, lex.pos, lex.lim); nextlex(); } } /* inside smal32.onepass, string pool and symbol table management */ static void putch(ch) char ch; { /* put one char into permanent end of stringpool */ if (poolsp > poolpos) { /* there is room in pool */ poolpos++; strpool[poolpos - relsym] = ch; } else { /* there isn't room */ poolfull = true; } } static poolref putpool_(pos, lim) inbufptr pos, lim; { /* put the string between pos and lim-1 on the current line into the string pool, returning it's index in the pool. the string delimiter is appended to the string in the pool. it is assumed that the string will fit (the caller must guarantee this) */ poolref Result; inbufptr i; poolpos++; Result = poolpos; for (i = pos - 1; i <= lim - 2; i++) { strpool[poolpos - relsym] = line[i]; poolpos++; } strpool[poolpos - relsym] = pooldel; return Result; } static boolean poolfit(pos, lim) inbufptr pos, lim; { /* check to see if text between pos and lim will fit in stringpool */ /* poolfit */ return (poolsp - poolpos > lim - pos); } static boolean poolcmp(poolpos, pos, lim) poolref poolpos; inbufptr pos, lim; { /* compare the string starting at poolpos in the stringpool with that between pos and lim on the current line, return true if they are the same; this relies on the fact that the string delimiter in the stringpool will never occur in the line */ while (strpool[poolpos - relsym] == line[pos - 1]) { poolpos++; pos++; } return (strpool[poolpos - relsym] == pooldel && pos == lim); } static long hash_(pos, lim, modulus) inbufptr pos, lim; long modulus; { /* compute hash of lexeme between pos and lim, return a value between 1 and modulus (inclusive) this hash function must match that in "opinit" */ long acc; inbufptr p; /* hash */ acc = 1; for (p = pos - 1; p <= lim - 2; p++) { acc = (acc * 5 + line[p]) % modulus + 1; } return acc; } static symptr lookup(pos, lim) inbufptr pos, lim; { /* find the symbol between pos and lim on the current line in the symbol table, return the index into the table where it was found or inserted; if it could not be inserted, return zero */ symptr Result, s, olds; association *WITH; /* lookup */ s = hash_(pos, lim, (long)symsize); olds = s; Result = 0; /* default return value */ do { WITH = &symtab[s - 1]; if (WITH->id != 0) { /* with */ if (poolcmp(WITH->id, pos, lim)) { Result = s; s = olds; /* terminate loop */ } else { if (s < symsize) { s++; } else { s = 1; } if (s == olds) symfull = true; } } else { /* found unused table entry */ if (poolfit(pos, lim)) { /* put the symbol in the pool and table */ WITH->id = putpool_(pos, lim); Result = s; } else /* no room in pool for sym */ poolfull = true; s = olds; /* terminate loop */ } } while (s != olds); return Result; } static void symdump() { /* dump entire contents of symbol table */ symptr i; association *WITH; for (i = 0; i < symsize; i++) { WITH = &symtab[i]; if (WITH->id != 0) { /* have nonblank entry */ writesym(dmp, WITH->id); putc('=', dmp); putc('\t', dmp); /* sort field delimiter */ /* could use following */ /* genval( WITH->val.offset, WITH->val.base);*/ /* instead, we do it locally to get sortable format */ if (WITH->val.base != abssym) { if (WITH->val.base = relsym) { fputs("REL(0)", dmp); } else { writesym(dmp, WITH->val.base); } putc('+', dmp); } putc('\t', dmp); fputs("0x", dmp); writehex(dmp, WITH->val.offset, 8); putc('\n', dmp); } } } static opptr oplookup(pos, lim) inbufptr pos, lim; { /* find the symbol between pos and lim on the current line in the opcode table, return the index into the table where it was found or should be put; return 0 if it isn't found and the table is full */ opptr Result, s, olds; _REC_optab *WITH; s = hash_(pos, lim, (long)opcodes); olds = s; Result = 0; /* default return value */ do { WITH = &optab[s - 1]; if (WITH->id != 0) /* with */ { /* have nonblank entry */ if (poolcmp(WITH->id, pos, lim)) { /* found it */ Result = s; s = olds; /* terminate loop */ } else { if (s < opcodes) s++; else s = 1; } } else { /* found vacancy */ Result = s; s = olds; /* terminate loop */ } } while (s != olds); return Result; } /* inside smal32.onepass, utility parsing procedures */ static void getcomma() { /* skip the comma, complain if there isn't one */ if (lex.typ == comma) nextlex(); else errmsg(comexp, lex.pos, lex.lim); } static void getequals() { /* skip the comma, complain if there isn't one */ if (lex.typ == eq) nextlex(); else errmsg(equexp, lex.pos, lex.lim); } static void skipbal() { /* skip to maching end paren when given begin paren */ long nest; lexeme par; /* assert lex.typ = bpar */ nest = 1; par = lex; do { nextlex(); if (lex.typ == bpar) nest++; else if (lex.typ == epar) nest--; } while (nest >= 1 && lex.typ != eol); if (lex.typ == eol) errmsg(unbal, par.pos, par.lim); } static void expression(); static void value_() { /* parse values of an expression of the form ::= ! ! . ! ( ) ! ! ( ) return the value of the value in expr */ symptr symbol; lexeme op, par; long i; association *WITH; exprpos = lex.pos; exprlim = lex.lim; exprundef = false; if (lex.typ == num) { /* got a + 1number */ expr.offset = lex.UU.val; expr.base = abssym; exprdef = true; /* read over number */ nextlex(); } else if (lex.typ == quote) { expr.base = 0; expr.offset = 0; exprdef = true; i = lex.lim - lex.pos; if (i > 6) errmsg(bounds, lex.pos, lex.lim); else if (i > 2) { long FORLIM = lex.lim - lex.pos - 3; for (i = 0; i <= FORLIM; i++) expr.offset = expr.offset * 256 + line[lex.pos + i]; } nextlex(); } else if ((lex.typ == id) && (next.typ == bpar)) { /* do a named (unary) function */ op = lex; nextlex(); /* skip operator name */ par = lex; nextlex(); /* skip opening paren */ expr.base = abssym; expr.offset = 1; /* default to ambiguous */ exprdef = true; /* default to defined */ if (poolcmp(funcdf, op.pos, op.lim)) { if (lex.typ == id) /* skip operand */ symbol = lookup(lex.pos, lex.lim); else { symbol = 0; errmsg(idexp, lex.pos, lex.lim); } nextlex(); if (symbol != 0) expr.offset = -((setyetmask & symtab[symbol - 1].use) != 0); } else if (poolcmp(funcfw, op.pos, op.lim)) { if (lex.typ == id) /* skip operand */ symbol = lookup(lex.pos, lex.lim); else { symbol = 0; errmsg(idexp, lex.pos, lex.lim); } nextlex(); if (symbol != 0) expr.offset = -((usedyetmask & symtab[symbol - 1].use)!=0 && (setyetmask & symtab[symbol - 1].use)==0); } else if (poolcmp(functy, op.pos, op.lim)) { expression(); expr.offset = expr.base; expr.base = abssym; } else if (poolcmp(funcab, op.pos, op.lim)) { expression(); expr.base = abssym; } else if (poolcmp(funcrl, op.pos, op.lim)) { expression(); if (expr.base == abssym) { expr.base = relsym; } else { errmsg(badrel, exprpos, exprlim); } } else if (poolcmp(funcle, op.pos, op.lim)) { if (lex.typ == epar) expr.offset = 0; else { expr.offset = lex.pos; if (lex.typ == bpar) skipbal(); while ((next.typ != eol)&&(next.typ != epar)) { nextlex(); if (lex.typ == bpar) skipbal(); } expr.offset = lex.lim - expr.offset; nextlex(); } } else { errmsg(unfunc, op.pos, op.lim); while ((lex.typ != epar) && (lex.typ != eol)) nextlex(); } if (lex.typ == epar) { exprpos = op.pos; exprlim = lex.lim; /* skip end paren */ nextlex(); } else { errmsg(unbal, par.pos, par.lim); } } else if (lex.typ == id) { /* ah, just an ordinary identifier.. */ symbol = lookup(lex.pos, lex.lim); if (symbol > 0) { /* read over identifier */ WITH = &symtab[symbol - 1]; WITH->use |= usedyetmask; if ((defmask & WITH->use) != 0 || (labmask & WITH->use) != 0) { expr = WITH->val; exprdef = true; exprundef = ((setyetmask & WITH->use) == 0); } else { errmsg(undef, lex.pos, lex.lim); expr.offset = 0; expr.base = abssym; exprdef = false; } } else { /* if */ expr.offset = 0; /* no err on full table */ expr.base = abssym; exprdef = true; /* pretend it's defined */ } nextlex(); } else if (lex.typ == dot) { expr = loc; exprdef = true; /* read over dot */ nextlex(); } else if (lex.typ == bpar) { par = lex; nextlex(); expression(); if (lex.typ == epar) { exprpos = par.pos; exprlim = lex.lim; nextlex(); } else errmsg(unbal, par.pos, par.lim); } else { /* got something else */ errmsg(notval, lex.pos, lex.lim); expr.offset = 0; expr.base = abssym; exprdef = false; if (((1L << ((long)lex.typ)) & ((1L << ((long)epar)) | (1L << ((long)eol)) | (1L << ((long)comma)))) == 0) /* read over whatever it is */ nextlex(); } exprundef = (!exprdef || exprundef); } static void term() { /* parse terms of an expression of the form ::= [ ] return the value of the term in expr */ /* unary operator */ lexeme op; if ( (lex.typ != plus) && (lex.typ != minus) && (lex.typ != compsy) && (lex.typ != notsym) ) { /* not unary */ value_(); return; } op = lex; /* read over unary operator */ nextlex(); /* get value to be modified */ value_(); exprpos = op.pos; switch (op.typ) { /* case */ case plus: /* blank case */ break; case minus: if (expr.base == abssym) expr.offset = neg(expr.offset); else errmsg(badrel, op.pos, op.lim); break; case compsy: if (expr.base == abssym) expr.offset = inot(expr.offset); else errmsg(badrel, op.pos, op.lim); break; case notsym: if (expr.base == abssym) { if (expr.offset == 0) { expr.offset = 1; } else { expr.offset = 0; } } else { errmsg(badrel, op.pos, op.lim); } break; } } /* inside smal32.onepass, procedures to parse expressions */ static void expression() { /* parse expressions of the form ::= ! return the value of the expression in expr */ value acc; /* the accumulator */ boolean accdef; /* is the accumulator defined */ boolean accundef; /* does acc. have fwd ref(s)? */ lexeme op; /* what operator was found */ inbufptr expos; /* position of start of expression */ /* get leading term */ term(); acc = expr; accdef = exprdef; accundef = exprundef; expos = exprpos; /* save pos for error handlers */ while ( (lex.typ == plus) || (lex.typ == minus) || (lex.typ == gt) || (lex.typ == lt) || (lex.typ == eq) || ((lex.typ == notsym) && (lex.typ == eq)) || (lex.typ == andsym) || (lex.typ == orsym) ) { /* while loop processing terms */ op = lex; nextlex(); /* skip over operator */ /* what follows handles 2-token operators */ if (op.typ == eq) { if (lex.typ == eq) { nextlex(); /* fake == operator */ } } else if (op.typ == notsym) { /* assert (lex.typ == eq) */ nextlex(); } else if (op.typ == gt) { if (lex.typ == gt) { nextlex(); op.typ = epar; /* fake right shift op sym */ } else if (lex.typ == eq) { nextlex(); op.typ = comma; /* fake greater equal */ } } else if (op.typ == lt) { if (lex.typ == lt) { nextlex(); op.typ = bpar; /* fake left shift op sym */ } else if (lex.typ == eq) { nextlex(); op.typ = dot; /* fake less equal */ } } else if (op.typ == andsym) { if (lex.typ == andsym) { nextlex(); /* serious kluge && same as & */ } } else if (op.typ == orsym) { if (lex.typ == orsym) { nextlex(); /* serious kluge || same as | */ } } /* get following term */ term(); if (!exprdef) { accdef = false; continue; } switch (op.typ) { /* case */ case plus: /* plus */ acc.offset = add(acc.offset, expr.offset); if (acc.base == abssym) acc.base = expr.base; else if (expr.base != abssym) { errmsg(badrel, op.pos, op.lim); acc.base = abssym; } break; case minus: /* minus */ acc.offset = sub(acc.offset, expr.offset); if (acc.base == expr.base) acc.base = abssym; else if (expr.base != abssym) { errmsg(badrel, op.pos, op.lim); acc.base = abssym; } break; case dot: case comma: case eq: case notsym: case gt: case lt: if (acc.base == expr.base) { switch (op.typ) { /* case */ case gt: acc.offset =-(acc.offset > expr.offset); break; case comma: /* fake greater equal symbol */ acc.offset =-(acc.offset>=expr.offset); break; case lt: acc.offset =-(acc.offset < expr.offset); break; case dot: /* fake less equal symbol */ acc.offset =-(acc.offset<=expr.offset); break; case eq: acc.offset =-(acc.offset ==expr.offset); break; case notsym: acc.offset =-(acc.offset !=expr.offset); break; } acc.base = abssym; } else { /* gt,lt,eq */ errmsg(badrel, op.pos, op.lim); acc.base = abssym; acc.offset = 1; /* neither true nor false */ } break; case andsym: case orsym: if (acc.base == abssym && expr.base == abssym) { switch (op.typ) { /* case */ case andsym: acc.offset=iand(acc.offset,expr.offset); break; case orsym: acc.offset =ior(acc.offset,expr.offset); break; } } else /* andsym,orsym */ errmsg(badrel, op.pos, op.lim); break; case bpar: case epar: if (acc.base == abssym && expr.base == abssym) { if (expr.offset > 32) expr.offset = 32; while (expr.offset > 0) { switch (op.typ) { case bpar: acc.offset =add(acc.offset, acc.offset); break; case epar: acc.offset = rightshift(acc.offset); break; } expr.offset--; } } else { errmsg(badrel, op.pos, op.lim); } /* shift operators */ break; } } expr = acc; exprdef = accdef; exprundef = (exprundef || accundef || !exprdef); exprpos = expos; } static void expresbal() { /* evaluate expressions, assuring balanced parens */ /* expresbal */ expression(); while (lex.typ == epar) { errmsg(unbal, lex.pos, lex.lim); nextlex(); } } static void expresabs() { /* evaluate expression */ /* force absolute */ expresbal(); if (expr.base != abssym) { errmsg(badrel, exprpos, exprlim); expr.base = abssym; expr.offset = 0; } } static boundval( v, min, max ) long *v; long min, max; { /* check to see v is between min and max */ if ((*v < min) || (*v > max)) { errmsg( bounds, exprpos, exprlim ); *v = min; } } static boolean predicate() { /* evaluate expression */ /* evaluate predicates for if and elseif directives */ expresbal(); if (expr.base == abssym) { if (expr.offset == 0) { return false; } else { return true; } } else { errmsg(badrel, exprpos, exprlim); } return false; } /* inside smal32.onepass, processing of key syntactic elements */ static void labeldef() { /* parse label definition; define label and handle multiples */ symptr symbol; /* labeldef */ /* assume that (lex.typ = id) and (next.typ = colon) */ symbol = lookup(lex.pos, lex.lim); if (symbol > 0) { /* the symbol is in the table */ association *WITH = &symtab[symbol - 1]; if ((setyetmask & WITH->use) != 0) { errmsg(muldef, lex.pos, lex.lim); } else if ((labmask & WITH->use) != 0) { if (WITH->val.offset != loc.offset || WITH->val.base != loc.base) { errmsg(phase, lex.pos, lex.lim); } } else { WITH->val = loc; } WITH->use |= labmask | setyetmask; } nextlex(); /* read over id */ nextlex(); /* read over colon */ } static void definition( typ ) boolean typ; /* true for SET or =, false for EQU */ { /* parse and process definition of form = or of form EQU or SET */ symptr symbol; association *WITH; /* definition */ symbol = lookup(lex.pos, lex.lim); if (typ && ((labmask & symtab[symbol - 1].use) != 0)) { errmsg(muldef, lex.pos, lex.lim); } nextlex(); /* read over id */ nextlex(); /* read over = or EQU or SET */ expresbal(); if (symbol <= 0) return; WITH = &symtab[symbol - 1]; if (typ) { /* normal define */ WITH->use |= setyetmask; if (exprdef) { WITH->val = expr; WITH->use |= defmask; } } else { /* EQU */ if ((setyetmask & WITH->use) != 0) { errmsg(muldef, lex.pos, lex.lim); } else if (! exprdef) { /* don't gripe, the error has been reported already */ } else if ((labmask & WITH->use) != 0) { if (WITH->val.offset != expr.offset || WITH->val.base != expr.base) { errmsg(phase, lex.pos, lex.lim); } } else { WITH->val = expr; } WITH->use |= labmask | setyetmask; } } static void opcode() { /* parse opcode field, including detection of data width specifying suffices. Resultant info is returned via globals optype, opval, opsubt, opsufi, opsufi2, opsuff and opsufcc. */ opptr i; oppos = lex.pos; oplim = lex.lim; optype = operr; i = oplookup(oppos, oplim); if (i != 0) { if (optab[i - 1].id != 0) { _REC_optab *WITH = &optab[i - 1]; optype = WITH->typ; opval = WITH->val; opsubt = WITH->subtyp; } } nextlex(); } static void getop() { /* skip and ignore labels on a line, return the opcode globally suppress any error messages encountered in parsing the line */ startup(); while (lex.typ == id && next.typ == colon) { /* skip id */ nextlex(); /* skip colon */ nextlex(); } if (lex.typ == id) { if (next.typ == eq) optype = operr; else opcode(); } else optype = operr; erset = 0; } /* inside smal32.onepass, processing of external symbol linkages */ static void internl() { /* parse and process internal symbol definitions */ symptr symbol; if (lex.typ == id) { /* read over internal symbol name */ symbol = lookup(lex.pos, lex.lim); if (symbol > 0) { association *WITH = &symtab[symbol - 1]; WITH->use |= intdefmask; if ((WITH->use & (defmask | labmask)) == 0) /* if with */ errmsg(undef, lex.pos, lex.lim); } } else errmsg(idexp, lex.pos, lex.lim); nextlex(); } static void makeext(symbol) symptr symbol; { /* make or verify that the current symbol is external */ /* used only from externl and comdef */ association *WITH = &symtab[symbol - 1]; if ((setyetmask & WITH->use) != 0) errmsg(muldef, lex.pos, lex.lim); else if ((usedyetmask & WITH->use) != 0) errmsg(fwdref, lex.pos, lex.lim); else if ((labmask & WITH->use) != 0) { if (WITH->val.base != WITH->id || WITH->val.offset != 0) errmsg(muldef, lex.pos, lex.lim); } else { WITH->val.base = WITH->id; WITH->val.offset = 0; } WITH->use |= labmask | setyetmask; /* with */ /* symbol previously unused */ } static void externl() { /* parse and process external symbol declarations */ symptr symbol; /* externl */ if (lex.typ == id) { /* read over external symbol name */ symbol = lookup(lex.pos, lex.lim); if (symbol > 0) makeext(symbol); } else errmsg(idexp, lex.pos, lex.lim); nextlex(); } static void comdef() { /* parse and process common declarations */ symptr symbol; if (lex.typ != id) { errmsg(idexp, lex.pos, lex.lim); return; } symbol = lookup(lex.pos, lex.lim); if (symbol > 0) { association *WITH = &symtab[symbol - 1]; makeext(symbol); /* read over common name */ nextlex(); getcomma(); /* get common size or maximum location */ expresbal(); if (expr.base != abssym && expr.base != WITH->id) { errmsg(badrel, exprpos, exprlim); return; } expr.offset += expr.offset & 1; /* halfword align size */ expr.offset += expr.offset & 2; /* word align size */ if (!allowlist) return; fputs("IF\\DEF(S", obj); writesym(obj, WITH->id); fputs(")\n S", obj); writesym(obj, WITH->id); fputs("=#", obj); writehex(obj, expr.offset, 4L); fputs("\nENDIF\nIF\\DEF(R", obj); writesym(obj, WITH->id); fputs(")\n R", obj); writesym(obj, WITH->id); fputs("=C\n C=C+S", obj); writesym(obj, WITH->id); fputs("\n CT=.\n .=C\n .=CT\nENDIF\n",obj); return; } nextlex(); getcomma(); /* skip over size */ expresbal(); /* symbol table full */ /* skip over name */ /* common name missing */ } /* inside smal32.onepass, processing of text insertions */ static void insert_() { /* process use directive (push one input file on stack) */ int i; inbufptr pos; int startpos; pos = lex.pos + 1; if (lex.typ == lt) { /* quotation marks */ while ((lex.typ != gt) && (lex.typ != eol)) { nextlex(); } if (lex.typ != gt) { errmsg(misquo, lex.pos, lex.lim); nextlex(); return; } } else if (lex.typ != quote) { errmsg(quoexp, lex.pos, lex.lim); nextlex(); return; } if (getlevel >= maxgetl) { errmsg(maxuse, lex.pos, lex.lim); nextlex(); return; } /* put together the file name */ startpos = 1; if (line[pos - 1] != pathbrk) { /* relative path */ if (lex.typ == quote) { /* relative to source directory */ memcpy(infile[getlevel], infile[getlevel - 1], sizeof(filename)); for (i = 1; i < filelen; i++) { if (infile[getlevel][i - 1] == pathbrk) startpos = i + 1; } } else { /* relative to MAKEPATH */ strncpy(infile[getlevel], MAKEPATH, sizeof(filename)); startpos = 1; while (infile[getlevel][startpos - 1] != '\0') { startpos++; } infile[getlevel][startpos - 1] = pathbrk; startpos++; } } for (i = startpos - 1; i < filelen; i++) { if (pos < lex.lim - 1) { infile[getlevel][i] = line[pos - 1]; pos++; } else infile[getlevel][i] = 0; } /* try to open the file */ if (inp[getlevel] != NULL) { inp[getlevel] = freopen(infile[getlevel], "r", inp[getlevel]); } else { inp[getlevel] = fopen(infile[getlevel], "r"); } if (inp[getlevel] == NULL) { /* see if it worked */ errmsg(baduse, lex.pos, lex.lim); } else { /* if it worked, save current source */ pushget(); getlevel++; gettext = 0; /* set source to file, not macro */ actcnt = 0; /* set to no macro parameters */ } nextlex(); } /* static variables for macdef: */ static poolref parmtab[parmlim]; static int parms; static poolref _oldsp; static void getpar() { /* getpar */ /* parse one formal parameter of form: := ! ( ) ! = corresponding to by name, by list of names, and by value */ /* the parameter identifier */ lexeme _parm; /* the position of the begin paren */ lexeme par; /* the type of the formal parameter */ char typ = ' '; if (parms < parmlim) { /* read over parameter */ if (lex.typ == id) { /* name parameter */ _parm = lex; typ = 'a'; } else if (lex.typ == eq) { nextlex(); if (lex.typ == id) { typ = '='; _parm = lex; } else { _parm.typ = eol; errmsg(idexp, lex.pos, lex.lim); } } else if (lex.typ == bpar) { par = lex; /* hold onto position for errors */ /* skip over paren */ nextlex(); if (lex.typ == id) { typ = '('; _parm = lex; nextlex(); /* skip over identifier */ if (lex.typ != epar) errmsg(unbal, par.pos, par.lim); } else { _parm.typ = eol; errmsg(idexp, lex.pos, lex.lim); } } else { _parm.typ = eol; errmsg(idexp, lex.pos, lex.lim); } if (_parm.typ == id) { /* have a good param */ parms++; if (firstpass) { parmtab[parms-1] = pushtext(_parm.pos, _parm.lim); putch(typ); } } } else { errmsg(parovf, lex.pos, lex.lim); } nextlex(); } static parm lookup_(pos, lim) inbufptr pos, lim; { /* lookup candidate formal parameter name */ parm Result, i; /* lookup */ Result = 0; i = 0; while (i < parms) { i++; if (poolcmp(parmtab[i - 1], pos, lim)) { Result = i; i = parms; } } return Result; } static void getbody() { /* parse macro body of form: ::= endmac */ /* counter to find right endmac when nested */ long nest; inbufptr pos; /* progress pointers for parameter scan */ inbufptr lim; /* identity of current parameter */ parm parmnum; /* getbody */ nest = 1; do { if (listing) listline(); getop(); if (optype == opmac) nest++; else if (optype == opendm) nest--; else if (optype == opend) nest = 0; if (nest > 0 && firstpass) { /* save text */ pos = 1; while (pos <= length) { while (!(charclass[line[pos - 1]] & isalpha) && (pos <= length) ) { /* copy non identifier text */ if (line[pos - 1] == '`') { /* squeeze out a quote mark */ pos++; /* assert line[length+1]=';' */ while (line[pos - 1] == '`') { putch('`'); pos++; } } else { /* pass through simple text */ putch(line[pos - 1]); pos++; } } if (pos > length) break; /* found an identifier */ lim = pos; while (charclass[line[lim - 1]] & isalphanum) lim++; /* length of identifier known */ parmnum = lookup_(pos, lim); if (parmnum > 0) { /* identifier is a macro formal parm */ putch(pooldel); putch(parmnum + '0'); } else { /* identifier is just text */ for (pos--; pos <= lim - 2; pos++) putch(line[pos]); } pos = lim; } putch(pooldel); putch(','); } } while (nest >= 1); poolsp = _oldsp; /* pop formal parameter table from stack */ if (optype == opend) { /* found end of file, not endm */ errmsg(misemc, 0, 0); popget(); } if (firstpass) { putch(pooldel); /* two pooldel's in a row end a macro */ putch(pooldel); } } static void macdef(skipmac) boolean skipmac; /* should keyword MACRO be skipped between name and params */ { /* process macro definitions of the forms: macro [ [ , ]* ] macro [ [ , ]* ] in both cases, parsing begins on the name */ opptr m; parms = 0; _oldsp = poolsp; /* mark stack top, allowing temporary use */ if (lex.typ == id) { /* have macro name */ m = oplookup(lex.pos, lex.lim); if (m <= 0) /* skip over macro name */ { /* no room in table */ opfull = true; } else if (firstpass) { if (optab[m - 1].id == 0) { /* first definition */ if (poolfit(lex.pos, lex.lim)) { optab[m - 1].id = putpool_(lex.pos, lex.lim); optab[m - 1].typ = opmcall; optab[m - 1].val = poolpos + 1; } } else { /* redefinition */ optab[m - 1].typ = opmcall; optab[m - 1].val = poolpos + 1; } } nextlex(); /* advance over name */ if (skipmac) nextlex(); /* skip keyword MACRO */ if (lex.typ != eol) { getpar(); while (lex.typ != eol) { getcomma(); getpar(); } } if (firstpass) /* mark end of parmtypes */ putch(pooldel); } else { /* missing macro name */ errmsg(idexp, lex.pos, lex.lim); /* skip over junk */ nextlex(); } if (lex.typ != eol && erset == 0) errmsg(unproc, lex.pos, lex.lim); getbody(); } /* static variables for maccall: */ static poolref _poolpos; static void getpar_() { /* parse a parameter of the form: ::= [ ]* ! ! ( [ ]* ) [ : [ : ] ] */ char typ; /* indicates expected parameter type */ inbufptr pos; /* location of parameter */ inbufptr lim; /* position info for begin paren */ lexeme par; typ = strpool[_poolpos - relsym]; _poolpos++; actcnt++; if (((1L << ((long)lex.typ)) & ((1L << ((long)comma)) | (1L << ((long)eol)))) != 0) { /* parameter missing */ actparm[actcnt - 1] = 0; return; } if (typ == 'a') { pos = lex.pos; lim = lex.lim; while (((1L << ((long)lex.typ)) & ((1L << ((long)eol)) | (1L << ((long)comma)))) == 0) { if (lex.typ == bpar) skipbal(); else if (lex.typ == epar) errmsg(unbal, lex.pos, lex.lim); lim = lex.lim; nextlex(); } actparm[actcnt - 1] = pushtext(pos, lim); return; } if (typ == '=') { expresbal(); /* recall that text is pushed backwards */ pushitxt(expr.offset); /* end with decimal offset */ if (expr.base != abssym) { /* add in correction for relocatable symbols */ pushchar('+'); if (expr.base == relsym) { /* actual param is REL(0)+offset */ pushchar(')'); pushchar('0'); pushchar('('); pushchar('L'); pushchar('E'); pushchar('R'); actparm[actcnt - 1] = poolsp + 1; } else { /* actual param is external+offset */ short int i = expr.base - relsym; short int j; for (j = i; strpool[j] != pooldel; j++); for (j--; j >= i; j--) { pushchar(strpool[j]); } } } actparm[actcnt - 1] = poolsp + 1; return; } if (typ != '(') return; if (lex.typ != bpar) { errmsg(parexp, lex.pos, lex.lim); nextlex(); return; } par = lex; /* skip paren at list head */ nextlex(); pos = lex.pos; lim = pos; /* default for empty string */ while (((1L << ((long)lex.typ)) & ((1L << ((long)eol)) | (1L << ((long)epar)))) == 0) { if (lex.typ == bpar) skipbal(); lim = lex.lim; nextlex(); } if (lex.typ == eol) errmsg(unbal, par.pos, par.lim); else nextlex(); if (lex.typ == colon) { /* substring */ nextlex(); if (lex.typ != colon) { /* get start */ expresbal(); if (expr.base != abssym) errmsg(badrel, exprpos, exprlim); if (expr.offset > 1) { if (expr.offset > lim - pos) pos = lim; else pos += expr.offset - 1; } } if (lex.typ == colon) { nextlex(); /* get length */ expresbal(); if (expr.base != abssym) errmsg(badrel, exprpos, exprlim); if (expr.offset < lim - pos) { if (expr.offset < 1) lim = pos; else lim = pos + expr.offset; } } } if (pos >= lim) actparm[actcnt - 1] = 0; else actparm[actcnt - 1] = pushtext(pos, lim); } static void maccall(poolpos_) poolref poolpos_; { /* call macro who's text is stored at poolpos in string pool; form of call is: [ [ , ]* ] */ /* save previous macro expansion status block */ _poolpos = poolpos_; if (poolfull) { /* stop bad calls */ } else { pushget(); actcnt = 0; while (strpool[_poolpos-relsym] != pooldel && lex.typ != eol) { getpar_(); if (lex.typ != eol) getcomma(); } if (lex.typ != eol) errmsg(parovf, lex.pos, lex.lim); while (strpool[_poolpos - relsym] != pooldel) _poolpos++; gettext = _poolpos + 1; /* set to read macro text from pool */ } } /* inside smal32.onepass, processing of conditional directives */ static void findend() { /* skip over lines until a line with endif or end opcode found */ long nest; nest = 0; do { /* read and check following lines */ /* first list previous line */ if (listing) listline(); getop(); if ( (optype == opif) || (optype == opifdf) || (optype == opifndf) ) { nest++; } else if (optype == opendif) { nest--; } } while (optype != opend && nest >= 0); if (optype == opend) { errmsg(miseif, 0, 0); popget(); } } static void findelse() { /* skip lines until one with an else, elseif , or end found */ do { /* read over then parts (allowing multiple elseif's) */ if (lex.typ != eol && erset == 0) errmsg(unproc, lex.pos, lex.lim); do { /* list line to be skipped */ if (listing) listline(); getop(); while ( (optype == opif) || (optype == opifdf) || (optype == opifndf) ) { findend(); /* list end */ if (listing) listline(); if (optype == opend) optype = opendif; /* don't complain twice */ else getop(); } } while (((1L << ((long)optype)) & ((1L << ((long)opend)) | (1L << ((long)opendif)) | (1L << ((long)opelse)))) == 0); } while (((1L << ((long)optype)) & ((1L << ((long)opend)) | (1L << ((long)opendif)) | (1L << ((long)opelse)))) == 0); if (optype == opend) { errmsg(miseif, 0, 0); popget(); } } /* inside smal32, main assembly procedure for one pass through source */ static void onepass() { /* perform one assembly pass. produce output if listing=true */ /* max val of loc.offset when loc.base = relsym */ long maxrel; poolsp = poolsize; gettext = 0; getlevel = 0; oldsp = 0; actcnt = 0; /* put a dummy level on the stack to allow clean end */ pushget(); getlevel = 1; /* setup for reading at normal source level */ listlevel = 1; /* setup so it will list only main level source */ lineonpg = linesper; /* force leading page-eject */ codelen = 0; /* no code yet accumulated for listing */ sbttllen = 0; /* no subtitle on first page-eject */ lineno = 0; errorcount = 0; loc.offset = 0; loc.base = relsym; maxram = 0xFFFF; config = 0x0000; radix = 16; maxrel = 0; objloc = loc; clearuse(); while (getlevel >= 1) { /* process one line per iteration */ listing = (listlevel > 0 && allowlist); startup(); /* setup for processing a line */ while (lex.typ == id && next.typ == colon) { labeldef(); } /* now know that if lex.typ = id, then next.typ <> colon */ if (lex.typ == id) { if (next.typ == eq) { /* process definitions */ definition(true); } else if ( (next.typ == id) && poolcmp(symset, next.pos, next.lim) ) { /* process SET definitions */ definition(true); } else if ( (next.typ == id) && poolcmp(symequ, next.pos, next.lim) ) { /* process EQU definitions */ definition(false); } else if ( (next.typ == id) && poolcmp(symmac, next.pos, next.lim) ) { macdef(true); } else { /* if */ opcode(); switch (optype) { /* opcode class */ case operr: errmsg(baddir, oppos, oplim); break; case opdata: /* data */ expresbal(); putobj(1L, expr.offset, expr.base); while (lex.typ != eol) { getcomma(); expresbal(); putobj(1L, expr.offset, expr.base); } break; case opif: if (!predicate()) findelse(); break; case opifdf: { if (lex.typ == id) { /* operand to test */ symptr symbol; symbol = lookup(lex.pos, lex.lim); nextlex(); if ( (symbol != 0) && ((setyetmask & symtab[symbol-1].use) == 0) ) { findelse(); } } else { /* operand missing */ errmsg(idexp, lex.pos, lex.lim); } } break; case opifndf: { if (lex.typ == id) { /* operand to test */ symptr symbol; symbol = lookup(lex.pos, lex.lim); nextlex(); if ( (symbol != 0) && ((setyetmask & symtab[symbol-1].use) != 0) ) { findelse(); } } else { /* operand missing */ errmsg(idexp, lex.pos, lex.lim); } } break; case opelse: findend(); break; case opendif: /* blank case */ break; case opint: /* internal definition */ internl(); while (lex.typ == comma) { nextlex(); internl(); } break; case opext: /* external definition */ externl(); while (lex.typ == comma) { nextlex(); externl(); } break; case opcomon: /* common definition */ comdef(); break; case opmac: /* process macro definition */ macdef(false); break; case opendm: errmsg(baddir, oppos, oplim); break; case opincl: /* insert text from alt file */ insert_(); break; case oporg: /* set assembly origin */ expresbal(); loc = expr; break; case opres: /* advance assembly origin */ expresabs(); loc.offset = add(loc.offset, expr.offset); break; case opconfg: /* set config word */ expresabs(); config = expr.offset; break; case opmax: /* set maxram */ expresabs(); maxram = expr.offset; break; case oplist: /* control listing */ if ((lex.typ == id) && poolcmp(symn, lex.pos, lex.lim)) { int saveradix = radix; nextlex(); /* skip 'n' */ getequals(); radix = 10; expresabs(); linesper = expr.offset; radix = saveradix; } else if (lex.typ == eol) { if (listlevel <= 0) listlevel = 1; listing = (listlevel > 0 && allowlist); } else { expresbal(); if (expr.base != abssym) errmsg(badrel, exprpos, exprlim); else { listlevel += expr.offset; if (expr.offset < 0 && erset == 0) listing = (listlevel > 0 && allowlist); } } break; case opnolist: /* control listing */ if (listlevel > 0) listlevel = 0; listing = (listlevel > 0 && allowlist); break; case operror: /* force listing as error msg */ lex.typ = eol; /* ignore rest of this line */ errmsg(erropr, 0, 0); break; case opradix: /* set default radix */ radix = 10; expresabs(); boundval( &expr.offset, 2, 16 ); radix = expr.offset; break; case opttl: /* title directive */ settitle(titlebuf, &titlelen, lex.pos, length); lex.typ = eol; break; case opsbttl: if (firstpass) listline(); if (allowlist) settitle(sbttlbuf, &sbttllen, lex.pos, length); if (listing) newpage(); lex.typ = eol; break; case opeject: if (listing) lineonpg = linesper - 1; break; case opend: popget(); break; case opmcall: /* call the indicated macro */ maccall((int)opval); break; /* PIC instruction formats */ case opbyteor: /* byte oriented, as per Fig 15-1 */ { int d, f; expresabs(); boundval( &expr.offset, 0, maxram ); f = expr.offset & 0x007F; getcomma(); expresabs(); d = expr.offset & 0x0001; putobj(1L, opval + (d << 7) + f, abssym); } break; case opfile: { int f; expresabs(); boundval( &expr.offset, 0, maxram ); f = expr.offset & 0x007F; putobj(1L, opval + f, abssym); } break; case opsimple: putobj(1L, opval, abssym); break; case opbitor: { int b, f; expresabs(); boundval( &expr.offset, 0, maxram ); f = expr.offset & 0x007F; getcomma(); expresabs(); b = expr.offset & 0x0007; putobj(1L, opval + (b << 7) + f, abssym); } break; case opgen: { int k; expresabs(); k = expr.offset & 0x00FF; putobj(1L, opval + k, abssym); } break; case opgoto: { int k; expresabs(); k = expr.offset & 0x07FF; putobj(1L, opval + k, abssym); } break; } } } else if (lex.typ != eol) { errmsg(baddir, lex.pos, lex.lim); nextlex(); /* skip over junk to avoid extra errors */ } if (lex.typ != eol && erset == 0) errmsg(unproc, lex.pos, lex.lim); if (listing) listline(); if (loc.base == relsym) { if (ugt(loc.offset, maxrel)) maxrel = loc.offset; } } if (!allowlist) return; /* make sure object code ends at maxrel */ if (loc.base != relsym || loc.offset != maxrel) { fputs(" ORG", obj); genval( maxrel, relsym); } /* put out config word */ if (makehexfile) { loc.offset = 0x2007; loc.base = abssym; putobj(1L, config, abssym); } else { fputs(" __CONFIG", obj); genval( config, abssym); } if (!permitlisting) return; /* note error count in listing */ if (errorcount == 0) { fputs(" no errors\n", o); return; } else { fputs(" ", o); if (errorcount == 1) fputs(" 1 error", o); else { fputs(" ", o); writedec(o, errorcount, 1); fputs(" errors", o); } fputs(" in this assembly\n", o); } } /* inside smal32, procedures to do file setup and takedown */ static void getfiles(argc, argv) int argc; char *argv[]; { /* get file name from command line, store it in global "infile" suffix it with ".l" for "outfile", ".o" for "objfile" and ".d" for "dumpfile" */ int dot, i; infile[0][0] = 0; permitlisting = true; symtabdump = false; makehexfile = false; for (i = 1; i < argc; i++) { /* for each argument */ if (argv[i][0] == '-') { if (argv[i][1] == 'L') { permitlisting = false; } else if (argv[i][1] == 'D') { symtabdump = true; } else if (argv[i][1] == 'X') { makehexfile = true; } else { fputs("** invalid command line argument **\n", stderr); fputs(" ", stderr); fputs(argv[0], stderr); fputs(" [-D] [-X] file\n", stderr); fputs(" -D, include dump in listing\n", stderr); fputs(" -X, generate Intel hex file\n", stderr); exit(-1); /* error */ } } else { int j; if (infile[0][0] != 0) { fputs("** multiple input files **\n", stderr); exit(-1); /* error */ } for (j = 0; argv[i][j] != 0; j++) { if (j < filelen-3) infile[0][j] = argv[i][j]; } while (j < filelen) { infile[0][j] = 0; j++; } infile[0][filelen-1] = 0; } } if (infile[0][0] == 0) { fputs("** no input file specified **\n", stderr); exit(-1); /* error */ } dot = 0; titlelen = 0; for (i = 0; i < filelen; i++) { char ch = infile[0][i]; titlebuf[i] = ch; outfile[i] = ch; objfile[i] = ch; dumpfile[i] = ch; hexfile[i] = ch; if (ch == '.') { dot = i; } if (i < (ttlbuflen-2)) { titlebuf[i] = ch; if (ch != 0) titlelen = i; } if ((ch == 0) && (dot == 0)) { /* no suffix on file name */ dot = i; } } outfile[dot] = '.'; outfile[dot + 1] = 'l'; outfile[dot + 2] = 0; objfile[dot] = '.'; objfile[dot + 1] = 'o'; objfile[dot + 2] = 0; dumpfile[dot] = '.'; dumpfile[dot + 1] = 'd'; dumpfile[dot + 2] = 0; hexfile[dot] = '.'; hexfile[dot + 1] = 'x'; hexfile[dot + 2] = 0; } /* inside smal32 */ main(argc, argv) int argc; char *argv[]; { { /* setup to classify characters */ int i; for (i = 0; i < 256; i++) charclass[i] = 0; } classchar( "abcdefghijklmnopqrstuvwxyz", islower | isvalid ); classchar( "ABCDEFGHIJKLMNOPQRSTUVWXYZ_", isupper | isvalid ); classchar( "0123456789", isdigit | isvalid ); classchar( ":$,=><+-~@&|()[]", ispunc | isvalid ); classchar( "'\"", isquote | isvalid ); classchar( " ;#", isvalid ); obj = NULL; dmp = NULL; o = NULL; { int i; for (i = 0; i < maxgetl; i++) { inp[i] = NULL; } } getfiles(argc, argv); inp[0] = fopen(infile[0], "r"); if (inp[0] == NULL) { fputs("** cannot open input file **\n", stderr); exit(-1); /* abnormal termination */ } if (permitlisting) { o = fopen(outfile, "w"); if (o == NULL) { fputs("** cannot open object file **\n", stderr); exit(-1); /* abnormal termination */ } } obj = fopen(objfile, "w"); if (obj == NULL) { fputs("** cannot open listing file **\n", stderr); exit(-1); /* abnormal termination */ } if (makehexfile) { hex = fopen(hexfile, "w"); if (hex == NULL) { fputs("** cannot open hex file **\n", stderr); exit(-1); /* abnormal termination */ } } clearsym(); opinit(); lineonpg = 1; linesper = linesdefault; pagenum = 0; getdatetime(); /* firstpass */ firstpass = true; allowlist = false; onepass(); if (poolfull) { fputs("** string pool overflowed on pass 1 **\n", stderr); exit(-1); /* abnormal termination */ } inp[0] = freopen(infile[0], "r", inp[0]); if (inp[0] == NULL) { fputs("** cannot reopen input file **\n", stderr); exit(-1); /* abnormal termination */ } fputs("R=$\n", obj); /* object prefix */ /* secondpass */ firstpass = false; allowlist = true; onepass(); objsufx(); putchar('\n'); fputs(" ", stderr); if (errorcount == 0) { fputs(" no errors\n", stderr); } else if (errorcount == 1) { fputs(" 1 error\n", stderr); } else { writedec( stderr, errorcount, 1 ); fputs(" errors\n", stderr); } if (symfull) fputs("** symbol table overflowed **\n", stderr); if (poolfull) fputs("** string pool overflowed **\n", stderr); if (opfull) fputs("** macro name table full **\n", stderr); if (symtabdump) { dmp = fopen(dumpfile, "w"); if (dmp == NULL) { fputs("** cannot open dump file **\n", stderr); } else { symdump(); } } /* now close all files */ { int i; for (i = 0; i < maxgetl; i++) { if (inp[i] != NULL) fclose(inp[i]); } } if (o != NULL) fclose(o); if (obj != NULL) fclose(obj); if (hex != NULL) fputs(":00000001FF\n", hex); /* Intel Hex EOF mark */ fclose(hex); if (dmp != NULL) fclose(dmp); exit(0); /* normal termination */ } END-of-smalpic.c echo x - p16c72.inc cat >p16c72.inc << 'END-of-p16c72.inc' ; PIC 16C72 include file for SMALPIC assembler ;----------------------- ; PIC 16C7x CONFIG word field values and __CONFIG pseudoop ; (and them to make CONFIG word, so unused bits are 1 _CP_OFF EQU 0x3F7F _CP_ON EQU 0x004F _PWRTE_OFF EQU 0x3F7F _PWRTE_ON EQU 0x3F77 _WDT_OFF EQU 0x3F7B _WDT_ON EQU 0x3F7F _RC_OSC EQU 0x3F7F _HS_OSC EQU 0x3F7E _XT_OSC EQU 0x3F7D _LP_OSC EQU 0x3F7C ;----------------------- ; Misc pseudoops not supported by SMAL ;----------------------- MACRO BANKISEL =x IF x & 0x100 BSF STATUS,IRP ELSE BCF STATUS,IRP ENDIF ENDM MACRO BANKSEL =x IF x & 0x80 BSF STATUS,RP0 ELSE BCF STATUS,RP0 ENDIF IF x & 0x100 BSF STATUS,RP1 ELSE BCF STATUS,RP1 ENDIF ENDM MACRO CONSTANT x x ENDM MACRO DT =x RETLW x ENDM MACRO MESSG x ERROR x ENDM MACRO PAGESEL =x MOVLW x >> 8 MOVWF PCLATH ENDM MACRO PROCESSOR x ENDM ;----------------------- ; PIC16C72 registers - the base of the family ;----------------------- W EQU 0 F EQU 1 INDF EQU 0x00 TMR0 EQU 0x01 PCL EQU 0x02 STATUS EQU 0x03 FSR EQU 0x04 PORTA EQU 0x05 PORTB EQU 0x06 PORTC EQU 0x07 ____ = 0x08 ____ = 0x09 PCLATH EQU 0x0A INTCON EQU 0x0B PIR1 EQU 0x0C ____ = 0x0D TMR1L EQU 0x0E TMR1H EQU 0x0F T1CON EQU 0x10 TMR2 EQU 0x11 T2CON EQU 0x12 SSPBUF EQU 0x13 SSPCON EQU 0x14 CCPR1L EQU 0x15 CCPR1H EQU 0x16 CCP1CON EQU 0x17 ____ = 0x18 ____ = 0x19 ____ = 0x1A ____ = 0x1B ____ = 0x1C ____ = 0x1D ADRES EQU 0x1E ADCON0 EQU 0x1F ____ = 0x80 OPTION EQU 0x81 ____ = 0x82 ____ = 0x83 ____ = 0x84 TRISA EQU 0x85 TRISB EQU 0x86 TRISC EQU 0x87 ____ = 0x88 ____ = 0x89 ____ = 0x8A ____ = 0x8B PIE1 EQU 0x8C ____ = 0x8D PCON EQU 0x8E ____ = 0x8F ____ = 0x90 ____ = 0x91 PR2 EQU 0x92 SSPADD EQU 0x93 SSPSTAT EQU 0x94 ____ = 0x95 ____ = 0x96 ____ = 0x97 ____ = 0x98 ____ = 0x99 ____ = 0x9A ____ = 0x9B ____ = 0x9C ____ = 0x9D ____ = 0x9E ADCON1 EQU 0x9F __MAXRAM 0xBF ; STATUS bits C EQU 0x0 DC EQU 0x1 Z EQU 0x2 PD EQU 0x3 TO EQU 0x4 RP0 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RA bits RA0 EQU 0x0 RA1 EQU 0x1 RA2 EQU 0x2 RA3 EQU 0x3 RA4 EQU 0x4 RA5 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RB bits RB0 EQU 0x0 RB1 EQU 0x1 RB2 EQU 0x2 RB3 EQU 0x3 RB4 EQU 0x4 RB5 EQU 0x5 RB6 EQU 0x6 RB7 EQU 0x7 ; RC bits RC0 EQU 0x0 RC1 EQU 0x1 RC2 EQU 0x2 RC3 EQU 0x3 RC4 EQU 0x4 RC5 EQU 0x5 RC6 EQU 0x6 RC7 EQU 0x7 ; INTCON bits RBIF EQU 0x0 INTF EQU 0x1 T0IF EQU 0x2 RBIE EQU 0x3 INTE EQU 0x4 T0IE EQU 0x5 PEIE EQU 0x6 GIE EQU 0x7 ; PIR1 bits TMR1IF EQU 0x0 TMR2IF EQU 0x1 CCP1IF EQU 0x2 SSPIF EQU 0x3 ____ = 0x4 ____ = 0x5 ADIF EQU 0x6 ____ = 0x7 ; T1CON bits TMR1ON EQU 0x0 TMR1CS EQU 0x1 T1SYNC EQU 0x2 T1OSCEN EQU 0x3 T1CKPS0 EQU 0x4 T1CKPS1 EQU 0x5 ____ = 0x6 ____ = 0x7 ; T2CON bits T2CKPS0 EQU 0x0 T2CKPS1 EQU 0x1 TMR2ON EQU 0x2 TOUTPS0 EQU 0x3 TOUTPS1 EQU 0x4 TOUTPS2 EQU 0x5 TOUTPS3 EQU 0x6 ____ = 0x7 ; SSPCON bits SSPM0 EQU 0x0 SSPM1 EQU 0x1 SSPM2 EQU 0x2 SSPM3 EQU 0x3 CKP EQU 0x4 SSPEN EQU 0x5 SSPOV EQU 0x6 WCOL EQU 0x7 ; CCP1CON bits CCP1M0 EQU 0x0 CCP1M1 EQU 0x1 CCP1M2 EQU 0x2 CCP1M3 EQU 0x3 CCP1Y EQU 0x4 CCP1X EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADRES bits ADON EQU 0x0 ____ = 0x1 GODONE EQU 0x2 CHS0 EQU 0x3 CHS1 EQU 0x4 CHS2 EQU 0x5 ADCS0 EQU 0x6 ADCS1 EQU 0x7 ; OPTION bits PS0 EQU 0x0 PS1 EQU 0x1 PS2 EQU 0x2 PSA EQU 0x3 T0SE EQU 0x4 T0CS EQU 0x5 INTDEG EQU 0x6 RBPU EQU 0x7 ; PCON bits POR EQU 0x0 BOR EQU 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; SSPSTAT bits BF EQU 0x0 UA EQU 0x1 RW EQU 0x2 S EQU 0x3 P EQU 0x4 DA EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADCON1 bits PCFG0 EQU 0x0 PCFG1 EQU 0x1 PCFG2 EQU 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 END-of-p16c72.inc echo x - p16c73.inc cat >p16c73.inc << 'END-of-p16c73.inc' ; PIC 16C73 include file for SMALPIC assembler ;----------------------- ; PIC 16C7x CONFIG word field values and __CONFIG pseudoop ; (and them to make CONFIG word, so unused bits are 1 _CP_OFF EQU 0x3F7F _CP_ON EQU 0x004F _PWRTE_OFF EQU 0x3F7F _PWRTE_ON EQU 0x3F77 _WDT_OFF EQU 0x3F7B _WDT_ON EQU 0x3F7F _RC_OSC EQU 0x3F7F _HS_OSC EQU 0x3F7E _XT_OSC EQU 0x3F7D _LP_OSC EQU 0x3F7C ;----------------------- ; Misc pseudoops not supported by SMAL ;----------------------- MACRO BANKISEL =x IF x & 0x100 BSF STATUS,IRP ELSE BCF STATUS,IRP ENDIF ENDM MACRO BANKSEL =x IF x & 0x80 BSF STATUS,RP0 ELSE BCF STATUS,RP0 ENDIF IF x & 0x100 BSF STATUS,RP1 ELSE BCF STATUS,RP1 ENDIF ENDM MACRO CONSTANT x x ENDM MACRO DT =x RETLW x ENDM MACRO MESSG x ERROR x ENDM MACRO PAGESEL =x MOVLW x >> 8 MOVWF PCLATH ENDM MACRO PROCESSOR x ENDM ;----------------------- ; PIC16C72 registers - the base of the family ;----------------------- W EQU 0 F EQU 1 INDF EQU 0x00 TMR0 EQU 0x01 PCL EQU 0x02 STATUS EQU 0x03 FSR EQU 0x04 PORTA EQU 0x05 PORTB EQU 0x06 PORTC EQU 0x07 ____ = 0x08 ____ = 0x09 PCLATH EQU 0x0A INTCON EQU 0x0B PIR1 EQU 0x0C ____ = 0x0D TMR1L EQU 0x0E TMR1H EQU 0x0F T1CON EQU 0x10 TMR2 EQU 0x11 T2CON EQU 0x12 SSPBUF EQU 0x13 SSPCON EQU 0x14 CCPR1L EQU 0x15 CCPR1H EQU 0x16 CCP1CON EQU 0x17 ____ = 0x18 ____ = 0x19 ____ = 0x1A ____ = 0x1B ____ = 0x1C ____ = 0x1D ADRES EQU 0x1E ADCON0 EQU 0x1F ____ = 0x80 OPTION EQU 0x81 ____ = 0x82 ____ = 0x83 ____ = 0x84 TRISA EQU 0x85 TRISB EQU 0x86 TRISC EQU 0x87 ____ = 0x88 ____ = 0x89 ____ = 0x8A ____ = 0x8B PIE1 EQU 0x8C ____ = 0x8D PCON EQU 0x8E ____ = 0x8F ____ = 0x90 ____ = 0x91 PR2 EQU 0x92 SSPADD EQU 0x93 SSPSTAT EQU 0x94 ____ = 0x95 ____ = 0x96 ____ = 0x97 ____ = 0x98 ____ = 0x99 ____ = 0x9A ____ = 0x9B ____ = 0x9C ____ = 0x9D ____ = 0x9E ADCON1 EQU 0x9F __MAXRAM 0xBF ; STATUS bits C EQU 0x0 DC EQU 0x1 Z EQU 0x2 PD EQU 0x3 TO EQU 0x4 RP0 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RA bits RA0 EQU 0x0 RA1 EQU 0x1 RA2 EQU 0x2 RA3 EQU 0x3 RA4 EQU 0x4 RA5 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RB bits RB0 EQU 0x0 RB1 EQU 0x1 RB2 EQU 0x2 RB3 EQU 0x3 RB4 EQU 0x4 RB5 EQU 0x5 RB6 EQU 0x6 RB7 EQU 0x7 ; RC bits RC0 EQU 0x0 RC1 EQU 0x1 RC2 EQU 0x2 RC3 EQU 0x3 RC4 EQU 0x4 RC5 EQU 0x5 RC6 EQU 0x6 RC7 EQU 0x7 ; INTCON bits RBIF EQU 0x0 INTF EQU 0x1 T0IF EQU 0x2 RBIE EQU 0x3 INTE EQU 0x4 T0IE EQU 0x5 PEIE EQU 0x6 GIE EQU 0x7 ; PIR1 bits TMR1IF EQU 0x0 TMR2IF EQU 0x1 CCP1IF EQU 0x2 SSPIF EQU 0x3 ____ = 0x4 ____ = 0x5 ADIF EQU 0x6 ____ = 0x7 ; T1CON bits TMR1ON EQU 0x0 TMR1CS EQU 0x1 T1SYNC EQU 0x2 T1OSCEN EQU 0x3 T1CKPS0 EQU 0x4 T1CKPS1 EQU 0x5 ____ = 0x6 ____ = 0x7 ; T2CON bits T2CKPS0 EQU 0x0 T2CKPS1 EQU 0x1 TMR2ON EQU 0x2 TOUTPS0 EQU 0x3 TOUTPS1 EQU 0x4 TOUTPS2 EQU 0x5 TOUTPS3 EQU 0x6 ____ = 0x7 ; SSPCON bits SSPM0 EQU 0x0 SSPM1 EQU 0x1 SSPM2 EQU 0x2 SSPM3 EQU 0x3 CKP EQU 0x4 SSPEN EQU 0x5 SSPOV EQU 0x6 WCOL EQU 0x7 ; CCP1CON bits CCP1M0 EQU 0x0 CCP1M1 EQU 0x1 CCP1M2 EQU 0x2 CCP1M3 EQU 0x3 CCP1Y EQU 0x4 CCP1X EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADRES bits ADON EQU 0x0 ____ = 0x1 GODONE EQU 0x2 CHS0 EQU 0x3 CHS1 EQU 0x4 CHS2 EQU 0x5 ADCS0 EQU 0x6 ADCS1 EQU 0x7 ; OPTION bits PS0 EQU 0x0 PS1 EQU 0x1 PS2 EQU 0x2 PSA EQU 0x3 T0SE EQU 0x4 T0CS EQU 0x5 INTDEG EQU 0x6 RBPU EQU 0x7 ; PCON bits POR EQU 0x0 BOR EQU 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; SSPSTAT bits BF EQU 0x0 UA EQU 0x1 RW EQU 0x2 S EQU 0x3 P EQU 0x4 DA EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADCON1 bits PCFG0 EQU 0x0 PCFG1 EQU 0x1 PCFG2 EQU 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ;----------------------- ; PIC16C73 registers add the following registers ;----------------------- PIR2 EQU 0x0D RCSTA EQU 0x18 TXREG EQU 0x19 RCREG EQU 0x1A CCPR2L EQU 0x1B CCPR2H EQU 0x1C CCP2CON EQU 0x1D PIE2 EQU 0x8D TXSTA EQU 0x98 SPBRG EQU 0x99 __MAXRAM 0xFF ; PIR1 bits TXIF EQU 0x4 RCIF EQU 0x5 ; PIR2 bits CCP2IF EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; RCSTA bits RX9D EQU 0x0 OERR EQU 0x1 FERR EQU 0x2 ____ = 0x3 CREN EQU 0x4 SREN EQU 0x5 RX9 EQU 0x6 SPEN EQU 0x7 ; CCP2CON bits CCP2M0 EQU 0x0 CCP2M1 EQU 0x1 CCP2M2 EQU 0x2 CCP2M3 EQU 0x3 CCP2Y EQU 0x4 CCP2X EQU 0x5 ____ = 0x6 ____ = 0x7 ; PIE1 bits TMR1IE EQU 0x0 TMR2IE EQU 0x1 CCP1IE EQU 0x2 SSPIE EQU 0x3 TXIE EQU 0x4 RCIE EQU 0x5 ADIE EQU 0x6 ; PIE2 bits CCP2IE EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; TXSTA bits TX9D EQU 0x0 TRMT EQU 0x1 BRGH EQU 0x2 ____ = 0x3 SYNC EQU 0x4 TXEN EQU 0x5 TX9 EQU 0x6 CSRC EQU 0x7 END-of-p16c73.inc echo x - p16c74.inc cat >p16c74.inc << 'END-of-p16c74.inc' ; PIC 16C74 include file for SMALPIC assembler ;----------------------- ; PIC 16C7x CONFIG word field values and __CONFIG pseudoop ; (and them to make CONFIG word, so unused bits are 1 _CP_OFF EQU 0x3F7F _CP_ON EQU 0x004F _PWRTE_OFF EQU 0x3F7F _PWRTE_ON EQU 0x3F77 _WDT_OFF EQU 0x3F7B _WDT_ON EQU 0x3F7F _RC_OSC EQU 0x3F7F _HS_OSC EQU 0x3F7E _XT_OSC EQU 0x3F7D _LP_OSC EQU 0x3F7C ;----------------------- ; Misc pseudoops not supported by SMAL ;----------------------- MACRO BANKISEL =x IF x & 0x100 BSF STATUS,IRP ELSE BCF STATUS,IRP ENDIF ENDM MACRO BANKSEL =x IF x & 0x80 BSF STATUS,RP0 ELSE BCF STATUS,RP0 ENDIF IF x & 0x100 BSF STATUS,RP1 ELSE BCF STATUS,RP1 ENDIF ENDM MACRO CONSTANT x x ENDM MACRO DT =x RETLW x ENDM MACRO MESSG x ERROR x ENDM MACRO PAGESEL =x MOVLW x >> 8 MOVWF PCLATH ENDM MACRO PROCESSOR x ENDM ;----------------------- ; PIC16C72 registers - the base of the family ;----------------------- W EQU 0 F EQU 1 INDF EQU 0x00 TMR0 EQU 0x01 PCL EQU 0x02 STATUS EQU 0x03 FSR EQU 0x04 PORTA EQU 0x05 PORTB EQU 0x06 PORTC EQU 0x07 ____ = 0x08 ____ = 0x09 PCLATH EQU 0x0A INTCON EQU 0x0B PIR1 EQU 0x0C ____ = 0x0D TMR1L EQU 0x0E TMR1H EQU 0x0F T1CON EQU 0x10 TMR2 EQU 0x11 T2CON EQU 0x12 SSPBUF EQU 0x13 SSPCON EQU 0x14 CCPR1L EQU 0x15 CCPR1H EQU 0x16 CCP1CON EQU 0x17 ____ = 0x18 ____ = 0x19 ____ = 0x1A ____ = 0x1B ____ = 0x1C ____ = 0x1D ADRES EQU 0x1E ADCON0 EQU 0x1F ____ = 0x80 OPTION EQU 0x81 ____ = 0x82 ____ = 0x83 ____ = 0x84 TRISA EQU 0x85 TRISB EQU 0x86 TRISC EQU 0x87 ____ = 0x88 ____ = 0x89 ____ = 0x8A ____ = 0x8B PIE1 EQU 0x8C ____ = 0x8D PCON EQU 0x8E ____ = 0x8F ____ = 0x90 ____ = 0x91 PR2 EQU 0x92 SSPADD EQU 0x93 SSPSTAT EQU 0x94 ____ = 0x95 ____ = 0x96 ____ = 0x97 ____ = 0x98 ____ = 0x99 ____ = 0x9A ____ = 0x9B ____ = 0x9C ____ = 0x9D ____ = 0x9E ADCON1 EQU 0x9F __MAXRAM 0xBF ; STATUS bits C EQU 0x0 DC EQU 0x1 Z EQU 0x2 PD EQU 0x3 TO EQU 0x4 RP0 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RA bits RA0 EQU 0x0 RA1 EQU 0x1 RA2 EQU 0x2 RA3 EQU 0x3 RA4 EQU 0x4 RA5 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RB bits RB0 EQU 0x0 RB1 EQU 0x1 RB2 EQU 0x2 RB3 EQU 0x3 RB4 EQU 0x4 RB5 EQU 0x5 RB6 EQU 0x6 RB7 EQU 0x7 ; RC bits RC0 EQU 0x0 RC1 EQU 0x1 RC2 EQU 0x2 RC3 EQU 0x3 RC4 EQU 0x4 RC5 EQU 0x5 RC6 EQU 0x6 RC7 EQU 0x7 ; INTCON bits RBIF EQU 0x0 INTF EQU 0x1 T0IF EQU 0x2 RBIE EQU 0x3 INTE EQU 0x4 T0IE EQU 0x5 PEIE EQU 0x6 GIE EQU 0x7 ; PIR1 bits TMR1IF EQU 0x0 TMR2IF EQU 0x1 CCP1IF EQU 0x2 SSPIF EQU 0x3 ____ = 0x4 ____ = 0x5 ADIF EQU 0x6 ____ = 0x7 ; T1CON bits TMR1ON EQU 0x0 TMR1CS EQU 0x1 T1SYNC EQU 0x2 T1OSCEN EQU 0x3 T1CKPS0 EQU 0x4 T1CKPS1 EQU 0x5 ____ = 0x6 ____ = 0x7 ; T2CON bits T2CKPS0 EQU 0x0 T2CKPS1 EQU 0x1 TMR2ON EQU 0x2 TOUTPS0 EQU 0x3 TOUTPS1 EQU 0x4 TOUTPS2 EQU 0x5 TOUTPS3 EQU 0x6 ____ = 0x7 ; SSPCON bits SSPM0 EQU 0x0 SSPM1 EQU 0x1 SSPM2 EQU 0x2 SSPM3 EQU 0x3 CKP EQU 0x4 SSPEN EQU 0x5 SSPOV EQU 0x6 WCOL EQU 0x7 ; CCP1CON bits CCP1M0 EQU 0x0 CCP1M1 EQU 0x1 CCP1M2 EQU 0x2 CCP1M3 EQU 0x3 CCP1Y EQU 0x4 CCP1X EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADRES bits ADON EQU 0x0 ____ = 0x1 GODONE EQU 0x2 CHS0 EQU 0x3 CHS1 EQU 0x4 CHS2 EQU 0x5 ADCS0 EQU 0x6 ADCS1 EQU 0x7 ; OPTION bits PS0 EQU 0x0 PS1 EQU 0x1 PS2 EQU 0x2 PSA EQU 0x3 T0SE EQU 0x4 T0CS EQU 0x5 INTDEG EQU 0x6 RBPU EQU 0x7 ; PCON bits POR EQU 0x0 BOR EQU 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; SSPSTAT bits BF EQU 0x0 UA EQU 0x1 RW EQU 0x2 S EQU 0x3 P EQU 0x4 DA EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADCON1 bits PCFG0 EQU 0x0 PCFG1 EQU 0x1 PCFG2 EQU 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ;----------------------- ; PIC16C73 registers add the following registers ;----------------------- PIR2 EQU 0x0D RCSTA EQU 0x18 TXREG EQU 0x19 RCREG EQU 0x1A CCPR2L EQU 0x1B CCPR2H EQU 0x1C CCP2CON EQU 0x1D PIE2 EQU 0x8D TXSTA EQU 0x98 SPBRG EQU 0x99 __MAXRAM 0xFF ; PIR1 bits TXIF EQU 0x4 RCIF EQU 0x5 ; PIR2 bits CCP2IF EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; RCSTA bits RX9D EQU 0x0 OERR EQU 0x1 FERR EQU 0x2 ____ = 0x3 CREN EQU 0x4 SREN EQU 0x5 RX9 EQU 0x6 SPEN EQU 0x7 ; CCP2CON bits CCP2M0 EQU 0x0 CCP2M1 EQU 0x1 CCP2M2 EQU 0x2 CCP2M3 EQU 0x3 CCP2Y EQU 0x4 CCP2X EQU 0x5 ____ = 0x6 ____ = 0x7 ; PIE1 bits TMR1IE EQU 0x0 TMR2IE EQU 0x1 CCP1IE EQU 0x2 SSPIE EQU 0x3 TXIE EQU 0x4 RCIE EQU 0x5 ADIE EQU 0x6 ; PIE2 bits CCP2IE EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; TXSTA bits TX9D EQU 0x0 TRMT EQU 0x1 BRGH EQU 0x2 ____ = 0x3 SYNC EQU 0x4 TXEN EQU 0x5 TX9 EQU 0x6 CSRC EQU 0x7 ;----------------------- ; PIC16C74 and PIC16C77 add the following registers ;----------------------- PORTD EQU 0x08 PORTE EQU 0x08 TRISD EQU 0x88 TRISE EQU 0x88 ; PIR1 bits PSIF EQU 0x7 ; PIE1 bits PSPIE EQU 0x4 END-of-p16c74.inc echo x - p16c76.inc cat >p16c76.inc << 'END-of-p16c76.inc' ; PIC 16C76 include file for SMALPIC assembler ;----------------------- ; PIC 16C7x CONFIG word field values and __CONFIG pseudoop ; (and them to make CONFIG word, so unused bits are 1 _CP_OFF EQU 0x3F7F _CP_ON EQU 0x004F _PWRTE_OFF EQU 0x3F7F _PWRTE_ON EQU 0x3F77 _WDT_OFF EQU 0x3F7B _WDT_ON EQU 0x3F7F _RC_OSC EQU 0x3F7F _HS_OSC EQU 0x3F7E _XT_OSC EQU 0x3F7D _LP_OSC EQU 0x3F7C ;----------------------- ; Misc pseudoops not supported by SMAL ;----------------------- MACRO BANKISEL =x IF x & 0x100 BSF STATUS,IRP ELSE BCF STATUS,IRP ENDIF ENDM MACRO BANKSEL =x IF x & 0x80 BSF STATUS,RP0 ELSE BCF STATUS,RP0 ENDIF IF x & 0x100 BSF STATUS,RP1 ELSE BCF STATUS,RP1 ENDIF ENDM MACRO CONSTANT x x ENDM MACRO DT =x RETLW x ENDM MACRO MESSG x ERROR x ENDM MACRO PAGESEL =x MOVLW x >> 8 MOVWF PCLATH ENDM MACRO PROCESSOR x ENDM ;----------------------- ; PIC16C72 registers - the base of the family ;----------------------- W EQU 0 F EQU 1 INDF EQU 0x00 TMR0 EQU 0x01 PCL EQU 0x02 STATUS EQU 0x03 FSR EQU 0x04 PORTA EQU 0x05 PORTB EQU 0x06 PORTC EQU 0x07 ____ = 0x08 ____ = 0x09 PCLATH EQU 0x0A INTCON EQU 0x0B PIR1 EQU 0x0C ____ = 0x0D TMR1L EQU 0x0E TMR1H EQU 0x0F T1CON EQU 0x10 TMR2 EQU 0x11 T2CON EQU 0x12 SSPBUF EQU 0x13 SSPCON EQU 0x14 CCPR1L EQU 0x15 CCPR1H EQU 0x16 CCP1CON EQU 0x17 ____ = 0x18 ____ = 0x19 ____ = 0x1A ____ = 0x1B ____ = 0x1C ____ = 0x1D ADRES EQU 0x1E ADCON0 EQU 0x1F ____ = 0x80 OPTION EQU 0x81 ____ = 0x82 ____ = 0x83 ____ = 0x84 TRISA EQU 0x85 TRISB EQU 0x86 TRISC EQU 0x87 ____ = 0x88 ____ = 0x89 ____ = 0x8A ____ = 0x8B PIE1 EQU 0x8C ____ = 0x8D PCON EQU 0x8E ____ = 0x8F ____ = 0x90 ____ = 0x91 PR2 EQU 0x92 SSPADD EQU 0x93 SSPSTAT EQU 0x94 ____ = 0x95 ____ = 0x96 ____ = 0x97 ____ = 0x98 ____ = 0x99 ____ = 0x9A ____ = 0x9B ____ = 0x9C ____ = 0x9D ____ = 0x9E ADCON1 EQU 0x9F __MAXRAM 0xBF ; STATUS bits C EQU 0x0 DC EQU 0x1 Z EQU 0x2 PD EQU 0x3 TO EQU 0x4 RP0 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RA bits RA0 EQU 0x0 RA1 EQU 0x1 RA2 EQU 0x2 RA3 EQU 0x3 RA4 EQU 0x4 RA5 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RB bits RB0 EQU 0x0 RB1 EQU 0x1 RB2 EQU 0x2 RB3 EQU 0x3 RB4 EQU 0x4 RB5 EQU 0x5 RB6 EQU 0x6 RB7 EQU 0x7 ; RC bits RC0 EQU 0x0 RC1 EQU 0x1 RC2 EQU 0x2 RC3 EQU 0x3 RC4 EQU 0x4 RC5 EQU 0x5 RC6 EQU 0x6 RC7 EQU 0x7 ; INTCON bits RBIF EQU 0x0 INTF EQU 0x1 T0IF EQU 0x2 RBIE EQU 0x3 INTE EQU 0x4 T0IE EQU 0x5 PEIE EQU 0x6 GIE EQU 0x7 ; PIR1 bits TMR1IF EQU 0x0 TMR2IF EQU 0x1 CCP1IF EQU 0x2 SSPIF EQU 0x3 ____ = 0x4 ____ = 0x5 ADIF EQU 0x6 ____ = 0x7 ; T1CON bits TMR1ON EQU 0x0 TMR1CS EQU 0x1 T1SYNC EQU 0x2 T1OSCEN EQU 0x3 T1CKPS0 EQU 0x4 T1CKPS1 EQU 0x5 ____ = 0x6 ____ = 0x7 ; T2CON bits T2CKPS0 EQU 0x0 T2CKPS1 EQU 0x1 TMR2ON EQU 0x2 TOUTPS0 EQU 0x3 TOUTPS1 EQU 0x4 TOUTPS2 EQU 0x5 TOUTPS3 EQU 0x6 ____ = 0x7 ; SSPCON bits SSPM0 EQU 0x0 SSPM1 EQU 0x1 SSPM2 EQU 0x2 SSPM3 EQU 0x3 CKP EQU 0x4 SSPEN EQU 0x5 SSPOV EQU 0x6 WCOL EQU 0x7 ; CCP1CON bits CCP1M0 EQU 0x0 CCP1M1 EQU 0x1 CCP1M2 EQU 0x2 CCP1M3 EQU 0x3 CCP1Y EQU 0x4 CCP1X EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADRES bits ADON EQU 0x0 ____ = 0x1 GODONE EQU 0x2 CHS0 EQU 0x3 CHS1 EQU 0x4 CHS2 EQU 0x5 ADCS0 EQU 0x6 ADCS1 EQU 0x7 ; OPTION bits PS0 EQU 0x0 PS1 EQU 0x1 PS2 EQU 0x2 PSA EQU 0x3 T0SE EQU 0x4 T0CS EQU 0x5 INTDEG EQU 0x6 RBPU EQU 0x7 ; PCON bits POR EQU 0x0 BOR EQU 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; SSPSTAT bits BF EQU 0x0 UA EQU 0x1 RW EQU 0x2 S EQU 0x3 P EQU 0x4 DA EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADCON1 bits PCFG0 EQU 0x0 PCFG1 EQU 0x1 PCFG2 EQU 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ;----------------------- ; PIC16C73 registers add the following registers ;----------------------- PIR2 EQU 0x0D RCSTA EQU 0x18 TXREG EQU 0x19 RCREG EQU 0x1A CCPR2L EQU 0x1B CCPR2H EQU 0x1C CCP2CON EQU 0x1D PIE2 EQU 0x8D TXSTA EQU 0x98 SPBRG EQU 0x99 __MAXRAM 0xFF ; PIR1 bits TXIF EQU 0x4 RCIF EQU 0x5 ; PIR2 bits CCP2IF EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; RCSTA bits RX9D EQU 0x0 OERR EQU 0x1 FERR EQU 0x2 ____ = 0x3 CREN EQU 0x4 SREN EQU 0x5 RX9 EQU 0x6 SPEN EQU 0x7 ; CCP2CON bits CCP2M0 EQU 0x0 CCP2M1 EQU 0x1 CCP2M2 EQU 0x2 CCP2M3 EQU 0x3 CCP2Y EQU 0x4 CCP2X EQU 0x5 ____ = 0x6 ____ = 0x7 ; PIE1 bits TMR1IE EQU 0x0 TMR2IE EQU 0x1 CCP1IE EQU 0x2 SSPIE EQU 0x3 TXIE EQU 0x4 RCIE EQU 0x5 ADIE EQU 0x6 ; PIE2 bits CCP2IE EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; TXSTA bits TX9D EQU 0x0 TRMT EQU 0x1 BRGH EQU 0x2 ____ = 0x3 SYNC EQU 0x4 TXEN EQU 0x5 TX9 EQU 0x6 CSRC EQU 0x7 ;----------------------- ; PIC16C76 and PIC1C677 add the following ;----------------------- __MAXRAM 0x1EF ; STATUS bits RP1 EQU 0x6 IRP EQU 0x7 ; SSPSTAT bits CKE EQU 0x6 SMP EQU 0x7 END-of-p16c76.inc echo x - p16c77.inc cat >p16c77.inc << 'END-of-p16c77.inc' ; PIC 16C77 include file for SMALPIC assembler ;----------------------- ; PIC 16C7x CONFIG word field values and __CONFIG pseudoop ; (and them to make CONFIG word, so unused bits are 1 _CP_OFF EQU 0x3F7F _CP_ON EQU 0x004F _PWRTE_OFF EQU 0x3F7F _PWRTE_ON EQU 0x3F77 _WDT_OFF EQU 0x3F7B _WDT_ON EQU 0x3F7F _RC_OSC EQU 0x3F7F _HS_OSC EQU 0x3F7E _XT_OSC EQU 0x3F7D _LP_OSC EQU 0x3F7C ;----------------------- ; Misc pseudoops not supported by SMAL ;----------------------- MACRO BANKISEL =x IF x & 0x100 BSF STATUS,IRP ELSE BCF STATUS,IRP ENDIF ENDM MACRO BANKSEL =x IF x & 0x80 BSF STATUS,RP0 ELSE BCF STATUS,RP0 ENDIF IF x & 0x100 BSF STATUS,RP1 ELSE BCF STATUS,RP1 ENDIF ENDM MACRO CONSTANT x x ENDM MACRO DT =x RETLW x ENDM MACRO MESSG x ERROR x ENDM MACRO PAGESEL =x MOVLW x >> 8 MOVWF PCLATH ENDM MACRO PROCESSOR x ENDM ;----------------------- ; PIC16C72 registers - the base of the family ;----------------------- W EQU 0 F EQU 1 INDF EQU 0x00 TMR0 EQU 0x01 PCL EQU 0x02 STATUS EQU 0x03 FSR EQU 0x04 PORTA EQU 0x05 PORTB EQU 0x06 PORTC EQU 0x07 ____ = 0x08 ____ = 0x09 PCLATH EQU 0x0A INTCON EQU 0x0B PIR1 EQU 0x0C ____ = 0x0D TMR1L EQU 0x0E TMR1H EQU 0x0F T1CON EQU 0x10 TMR2 EQU 0x11 T2CON EQU 0x12 SSPBUF EQU 0x13 SSPCON EQU 0x14 CCPR1L EQU 0x15 CCPR1H EQU 0x16 CCP1CON EQU 0x17 ____ = 0x18 ____ = 0x19 ____ = 0x1A ____ = 0x1B ____ = 0x1C ____ = 0x1D ADRES EQU 0x1E ADCON0 EQU 0x1F ____ = 0x80 OPTION EQU 0x81 ____ = 0x82 ____ = 0x83 ____ = 0x84 TRISA EQU 0x85 TRISB EQU 0x86 TRISC EQU 0x87 ____ = 0x88 ____ = 0x89 ____ = 0x8A ____ = 0x8B PIE1 EQU 0x8C ____ = 0x8D PCON EQU 0x8E ____ = 0x8F ____ = 0x90 ____ = 0x91 PR2 EQU 0x92 SSPADD EQU 0x93 SSPSTAT EQU 0x94 ____ = 0x95 ____ = 0x96 ____ = 0x97 ____ = 0x98 ____ = 0x99 ____ = 0x9A ____ = 0x9B ____ = 0x9C ____ = 0x9D ____ = 0x9E ADCON1 EQU 0x9F __MAXRAM 0xBF ; STATUS bits C EQU 0x0 DC EQU 0x1 Z EQU 0x2 PD EQU 0x3 TO EQU 0x4 RP0 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RA bits RA0 EQU 0x0 RA1 EQU 0x1 RA2 EQU 0x2 RA3 EQU 0x3 RA4 EQU 0x4 RA5 EQU 0x5 ____ = 0x6 ____ = 0x7 ; RB bits RB0 EQU 0x0 RB1 EQU 0x1 RB2 EQU 0x2 RB3 EQU 0x3 RB4 EQU 0x4 RB5 EQU 0x5 RB6 EQU 0x6 RB7 EQU 0x7 ; RC bits RC0 EQU 0x0 RC1 EQU 0x1 RC2 EQU 0x2 RC3 EQU 0x3 RC4 EQU 0x4 RC5 EQU 0x5 RC6 EQU 0x6 RC7 EQU 0x7 ; INTCON bits RBIF EQU 0x0 INTF EQU 0x1 T0IF EQU 0x2 RBIE EQU 0x3 INTE EQU 0x4 T0IE EQU 0x5 PEIE EQU 0x6 GIE EQU 0x7 ; PIR1 bits TMR1IF EQU 0x0 TMR2IF EQU 0x1 CCP1IF EQU 0x2 SSPIF EQU 0x3 ____ = 0x4 ____ = 0x5 ADIF EQU 0x6 ____ = 0x7 ; T1CON bits TMR1ON EQU 0x0 TMR1CS EQU 0x1 T1SYNC EQU 0x2 T1OSCEN EQU 0x3 T1CKPS0 EQU 0x4 T1CKPS1 EQU 0x5 ____ = 0x6 ____ = 0x7 ; T2CON bits T2CKPS0 EQU 0x0 T2CKPS1 EQU 0x1 TMR2ON EQU 0x2 TOUTPS0 EQU 0x3 TOUTPS1 EQU 0x4 TOUTPS2 EQU 0x5 TOUTPS3 EQU 0x6 ____ = 0x7 ; SSPCON bits SSPM0 EQU 0x0 SSPM1 EQU 0x1 SSPM2 EQU 0x2 SSPM3 EQU 0x3 CKP EQU 0x4 SSPEN EQU 0x5 SSPOV EQU 0x6 WCOL EQU 0x7 ; CCP1CON bits CCP1M0 EQU 0x0 CCP1M1 EQU 0x1 CCP1M2 EQU 0x2 CCP1M3 EQU 0x3 CCP1Y EQU 0x4 CCP1X EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADRES bits ADON EQU 0x0 ____ = 0x1 GODONE EQU 0x2 CHS0 EQU 0x3 CHS1 EQU 0x4 CHS2 EQU 0x5 ADCS0 EQU 0x6 ADCS1 EQU 0x7 ; OPTION bits PS0 EQU 0x0 PS1 EQU 0x1 PS2 EQU 0x2 PSA EQU 0x3 T0SE EQU 0x4 T0CS EQU 0x5 INTDEG EQU 0x6 RBPU EQU 0x7 ; PCON bits POR EQU 0x0 BOR EQU 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; SSPSTAT bits BF EQU 0x0 UA EQU 0x1 RW EQU 0x2 S EQU 0x3 P EQU 0x4 DA EQU 0x5 ____ = 0x6 ____ = 0x7 ; ADCON1 bits PCFG0 EQU 0x0 PCFG1 EQU 0x1 PCFG2 EQU 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ;----------------------- ; PIC16C73 registers add the following registers ;----------------------- PIR2 EQU 0x0D RCSTA EQU 0x18 TXREG EQU 0x19 RCREG EQU 0x1A CCPR2L EQU 0x1B CCPR2H EQU 0x1C CCP2CON EQU 0x1D PIE2 EQU 0x8D TXSTA EQU 0x98 SPBRG EQU 0x99 __MAXRAM 0xFF ; PIR1 bits TXIF EQU 0x4 RCIF EQU 0x5 ; PIR2 bits CCP2IF EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; RCSTA bits RX9D EQU 0x0 OERR EQU 0x1 FERR EQU 0x2 ____ = 0x3 CREN EQU 0x4 SREN EQU 0x5 RX9 EQU 0x6 SPEN EQU 0x7 ; CCP2CON bits CCP2M0 EQU 0x0 CCP2M1 EQU 0x1 CCP2M2 EQU 0x2 CCP2M3 EQU 0x3 CCP2Y EQU 0x4 CCP2X EQU 0x5 ____ = 0x6 ____ = 0x7 ; PIE1 bits TMR1IE EQU 0x0 TMR2IE EQU 0x1 CCP1IE EQU 0x2 SSPIE EQU 0x3 TXIE EQU 0x4 RCIE EQU 0x5 ADIE EQU 0x6 ; PIE2 bits CCP2IE EQU 0x0 ____ = 0x1 ____ = 0x2 ____ = 0x3 ____ = 0x4 ____ = 0x5 ____ = 0x6 ____ = 0x7 ; TXSTA bits TX9D EQU 0x0 TRMT EQU 0x1 BRGH EQU 0x2 ____ = 0x3 SYNC EQU 0x4 TXEN EQU 0x5 TX9 EQU 0x6 CSRC EQU 0x7 ;----------------------- ; PIC16C76 and PIC1C677 add the following ;----------------------- __MAXRAM 0x1EF ; STATUS bits RP1 EQU 0x6 IRP EQU 0x7 ; SSPSTAT bits CKE EQU 0x6 SMP EQU 0x7 ;----------------------- ; PIC16C74 and PIC16C77 add the following registers ;----------------------- PORTD EQU 0x08 PORTE EQU 0x08 TRISD EQU 0x88 TRISE EQU 0x88 ; PIR1 bits PSIF EQU 0x7 ; PIE1 bits PSPIE EQU 0x4 END-of-p16c77.inc echo x - smalpicmake cat >smalpicmake << 'END-of-smalpicmake' # # smalpicmake (csh) cc -o smalpic -DMAKEPATH=\"`pwd`\" smalpic.c rm ~/bin/smalpic ln smalpic ~/bin/smalpic END-of-smalpicmake echo x - smalpicnotes cat >smalpicnotes << 'END-of-smalpicnotes' SMALpic Symbolic Macro Assembly Language for the PIC family of microprocessors (14-bit PIC architectures). COPYRIGHT 1999 Douglas W. Jones Permission is granted to make copies of this material for any purpose, provided that the above copyright notice is preserved in the copy, and provided that the copy is not made for direct commercial advantage. WARRANTEE None! This software has proven useful in the development of commercial software products, and I hope it proves useful to you, but you get what you pay for, and you paid nothing for this! COMMAND LINE FORMAT smalpic [options] infile the allowed options are: -L completely suppress generation of a listing file normally, the listing is generated to infile.l -D generate a dump of the symbol table to infile.d and infile.l normally, no symbol-table dump is generated -X generate output in Intel Hex format to infile.x normally, SMAL-format object code goes to infile.o, but this format is a fossil left over from other versions of SMAL. by convention, infile (the source file name) should have some kind of suffix like .a or .asm; the assembler strips off the suffix, if it is present, before adding new siffixes to make the object and listing files, but aside from that, the assembler ignores the suffix. SOURCE SYNTAX Blank lines in the assembly source are permitted. These are equivalent to comments. All comments begin with semicolons. The standard SMALpic assembly file begins something like the following: TITLE "Whatever title you want" LIST N=48 ; lines per page on listing INCLUDE The assembly file consists of a sequence of lines, where the lines take one of the following formats: label: opcode operands ; a normal assembly line with a label opcode operands ; a normal assembly line without a label opcode ; form used if the opcode has no operands symbol = expression ; define or redefine a symbol with a value symbol SET expression ; same as =, added for compatability symbol EQU expression ; define a symbol, forbidding redefinition symbol MACRO --- ; start of a macro definition The colon following a label must be present! Labels may start anywhere on the line, so it is legal to indent an entire block of code, including labels, macro names, etc. The set of opcodes supported includes the entire set of opcodes for Microchip's 14-bit PIC family, any macros defined, plus the following: general: DATA expression, expression, expression ... INCLUDE ; include a system include file INCLUDE "file" ; include from the user's directory __CONFIG expression ; set the config word of the object file __MAXRAM expression ; set the maximum RAM address allowed at assembly ORG expression ; set the assembly origin RES expression ; reserve memory space RADIX expression ; set the default radix anywhere from 2 to 16 END ; same as end of file! the following are defined as macros in the standard include files: BANKISEL expression ; generate indirect bank selection code BANKSEL expression ; generate direct addressing bank selection code PAGESEL expression ; generate page select code DT expression ; generate RETLW instruction for data table MESSG text ; same as ERROR PROCESSOR name ; kluge, does nothing but makes things look nice CONSTANT text ; kluge, listing control: LIST ; turn on listing LIST N=expression ; set lines per page LIST expression ; set number of levels of macro expansion to list NOLIST ; turn off listing PAGE ; force page eject in listing TITLE "title for listing" SUBTITLE "subtitle for listing, included in table of contents" SUBTITL "subtitle for listing, included in table of contents" ERROR ; always an error (use in macros for diagnostics) conditional assembly support: IF expression ; begin conditional assembly if true IFDEF symbol ; begin conditional assembly if defined IFNDEF symbol ; begin conditional assembly if not defined ELSE ENDIF macro assembly support: name MACRO p1,=p2,(p3) ; define macro and formal parameter names ENDM Note that the form of macro parameters is that of SMAL and not that of the Microchip family. In addition to simple macro paramters (compatable). SMALpic allows formal parameters of the form =x; the leading equals forces evaluation of expressions in the actual parameter and forces the substitution of the value of the expression for the actual parameter instead of substituing the text of the actual parameter. This is useful! SMALpic allows formal parameters of the form (x); See the machine-independent SMAL manual or the details. relics from SMAL (unlikely to be of use): INT EXT COMMON The support for relocation and linkage from SMAL has been largely broken by the move to the PIC world; it can probably be repaired, but when working with such tiny machines with such crippled memory addressing, it hardly seems worthwhile. Source code inclusion is perfectly adequate for all the projects I've done with 14-bit PICs. SMAL expressions consist of a sequence of terms separated by binary operators. All binary operators are evaluated left to right; if you want precidence, parenthesize! The operators are: binary arithmetic operators + -- binary addition - -- subtraction & -- bitwise and (works for boolean results as well) && -- same as &, a kluge, for compatability with Microchip | -- bitwise or (works for boolean results as well) || -- same as |, a kluge, for compatability with Microchip >> -- shift right << -- shift left comparison operators with boolean results (0 = false, 1 = true) > -- greater than >= -- greater than or equals < -- less than <= -- less than or equals = -- equals (not assignment!) == -- same as =, a kluge, for compatability with Microchip != -- not equals (for comparison, boolean result) Each term in an expression may be preceded by a unary operator. Binary operators take precidence over unary operators. These are: + -- no-op - -- unary two's complement negation ~ -- unary one's complement ! -- unary boolean negation (0 = false, 1 = true) Unary operators may be applied to any of the following: Id -- the value of an identifier such as Id 5 -- a numeric constant such as 5 . -- the location counter "string" -- a quoted string (usually just 1 character!) 'string' -- a quoted string (usually just 1 character!) ( expression ) -- any parenthesized expression func( expression ) -- a function applied to an expression The available functions are: functions applying to identifiers with boolean results. As (0 = false, 1 = true) DEF(id) -- true if id is already defined FWD(id) -- true if id has been referenced but not yet defined functions applying to general expressions LEN(expr) -- returns the length, in characters, of the expression (this is useful primarily in macros, to check the length of string parameters and to check to see if a parameter is present) The expression is not evaluated and the only syntax check is for balanced parentheses. Functions that are relics of SMAL that are unlikely to be used TYP(expr) -- returns the type (relocation base) of an expression ABS(expr) -- returns the absolute value of a relocatable expression REL(expr) -- makes an absolute expression relocatable END-of-smalpicnotes exit