home *** CD-ROM | disk | FTP | other *** search
- Subject: v09i026: Generic assembler for micro's, Part01/02
- Newsgroups: mod.sources
- Approved: rs@mirror.TMC.COM
-
- Submitted by: cisden!lmc (Lyle McElhaney)
- Mod.sources: Volume 9, Issue 26
- Archive-name: assem2/Part01
-
- echo extracting - README
- sed 's/^X//' > README << '@FUNKY STUFF~'
- XThis is the second posting of the generic assembler. Some notes:
- X
- X- I broke it down into some modules to assist recompilation.
- X
- X- As several have noted, this is not a modern assembler; its modelled
- Xafter the vintage assemblers of my youth, where the ops were ops, and
- Xoperands were operands, and operands didn't go around trying to be ops,
- Xand.... (sorry - too many movies lately). Anyway, that was to make it
- Xgeneric; its more difficult the other way. Problem is that it makes doing
- Xthe 6805 and 6809 quite messy. I experimented with extending the current
- Xregime to the 6809, and am disappointed by the results (to put it mildly -
- Xashamed would be closer). Anyway, I have to send this off with the problem
- Xunsolved as of now. I'm open to ideas.
- X
- X- Several bug fixes from Mark Callaghan in Australia: VAX byte swapping (I
- Xdid the work on a Sun, and forgot about the other wretched machines);
- Xchecksumming the address & byte count (and negating it); a casting problem
- Xin putoutbin; and adding an error if no end statemnt is found (and
- Xsimulating it anyway). Thanks, Mark.
- X
- X- An error in the 6502 was fixed.
- X
- X- Made the instruction mask long.
- X
- X- Makeops is a filter that adds a sort of macro capability to the creating
- Xof the ops.h files. See 6809_ops.h (but ignore the content - its grotesque).
- X
- X- At this time I'm porting it to an AT. Will repost when that's complete.
- X
- X--------------------------------------------------------------------------
- X
- XSimplicity itself: edit the Makefile, equating V to the machine number of
- Xthe assembler to be made, and say make. You've got an assembler.
- X
- XMachines available: 6502, 8085, 6803, 6809.
- X
- X6803reg.h has some specific register names for special hardware registers
- Xon the 6803.
- X
- XI would appreciate getting back any new ops.h files anyone cares to
- Xgenerate (or maybe regenerate). Send them to hao!cisden!lmc, or to
- X
- X Lyle McElhaney
- X 2489 W. Ridge Road
- X Littleton, CO 80120
- X
- XPS: Equates in asm.h may need tweaking (like NORMBYTE, fer instance).
- @FUNKY STUFF~
- echo extracting - Makefile
- sed 's/^X//' > Makefile << '@FUNKY STUFF~'
- XOBJS=asm.o instructions.o pseudos.o data.o
- XV=6502
- XCFLAGS=-O
- X
- Xasm: $(OBJS)
- X cc $(OBJS) -o asm
- X
- X$(OBJS): asm.h
- X
- Xdata.o: ops.h
- X
- Xops.h: $V_ops.h makeops
- X makeops <$V_ops.h >ops.h
- X
- Xmakeops: makeops.o
- X cc makeops.o -o makeops
- X
- Xclean:
- X rm -f asm makeops ops.h *.o dist_asm*
- X
- Xdistrib: clean
- X shar README Makefile *.c *.[1-9] > dist_asm1
- X shar *.h > dist_asm2
- X ls -l dist*
- @FUNKY STUFF~
- echo extracting - asm.c
- sed 's/^X//' > asm.c << '@FUNKY STUFF~'
- X#include "asm.h"
- X
- Xmain (argc, argv)
- X int argc;
- X char **argv;
- X{
- X char *t1, *t2;
- X
- X srcin = stdin;
- X filename[0] = "stdin";
- X binout = stdout;
- X getargs (argc, argv);
- X init ();
- X output = fopen ((t1 = mktemp ("/tmp/asm185XXXXXX")), "w+");
- X input[0] = srcin;
- X if (process ()) reporterr (E_PASS1);
- X (void) fclose (input[0]);
- X init2 ();
- X rewind (output);
- X input[0] = output;
- X output = fopen ((t2 = mktemp ("/tmp/asm285XXXXXX")), "w+");
- X if (process ()) reporterr (E_PASS2);
- X (void) fclose (input[0]);
- X (void) unlink (t1);
- X input[0] = output;
- X output = binout;
- X rewind (input[0]);
- X sort ();
- X (void) fclose (input[0]);
- X (void) unlink (t2);
- X (void) fclose (output);
- X if (xref) crossref ();
- X exit (errorstat);
- X}
- X
- X
- X/* Current arguments:
- X infile input file name (default stdin)
- X -lfile listing output to file (default no listing),
- X (default file is infile.l);
- X -ofile binary output to file (default binary to stdout),
- X (default file is infile.o);
- X -xfile cross reference output to listing file (default no xref);
- X*/
- Xvoid getargs (argc, argv)
- X int argc;
- X char **argv;
- X{
- X char *cp, *arg, *lname, *oname;
- X
- X while (--argc) {
- X arg = *(++argv);
- X if (*arg == '-') {
- X switch (*(++arg)) {
- X case 'l':
- X listing ++;
- X lname = ++arg;
- X break;
- X case 'o':
- X binary ++;
- X oname = ++arg;
- X break;
- X case 'x':
- X xref ++;
- X break;
- X }
- X } else {
- X name = arg;
- X if ((srcin = fopen (name, "r")) == NULL)
- X reporterr (E_INPUT);
- X filename[0] = strcpy (malloc ((unsigned) strlen (name) + 1), name);
- X if (cp = index (name, '.'))
- X *cp = '\0';
- X }
- X }
- X if (binary) {
- X if (!*oname) {
- X (void) strcat (strcpy (buf, name), ".o");
- X oname = buf;
- X }
- X binout = fopen (oname, "w");
- X }
- X if (listing || xref) {
- X if (!*lname) {
- X (void) strcat (strcpy (buf, name), ".l");
- X lname = buf;
- X }
- X list = fopen (lname, "w");
- X }
- X return;
- X}
- X
- X
- Xvoid init ()
- X{
- X symbol *spt;
- X int i;
- X
- X lc = seghd->lc = 0;
- X symtab = (symbol *) malloc ((unsigned) sizeof (symbol) * NSYMS);
- X for (i = 0; i < NSYMS; i++)
- X symtab->name = (char *) 0;
- X for (spt = predef; *(spt->name); spt++)
- X insert (spt->name, spt->value, spt->type, spt->segp, NO);
- X end_found = 0;
- X return;
- X}
- X
- X
- Xvoid init2 ()
- X{
- X segmnt *sp;
- X Memad acc;
- X
- X acc = seghd->lc;
- X seghd->lc = 0;
- X for (sp = seghd->next; sp; sp = sp->next) {
- X acc += sp->lc;
- X sp->lc = sp->start = acc - sp->lc;
- X }
- X curseg = seghd;
- X lc = curseg->lc;
- X errorstat =
- X end_found =
- X 0;
- X return;
- X}
- X
- X
- X
- X/* Gross syntax rules: <and the rest of us simply obey>
- X Input line: [label] [op[optop] [operands]]
- X Comments: Blank lines and anything following ';'
- X White space is any combination of blank and/or tab chars.
- X Operands & optop cannot contain white space (except within strings)
- X and are separated by commas. There must be the exact number of
- X operands that the instruction expects.
- X optop can be anything, and is interpreted by the machine-specific
- X routine "optional". It is distinguished from op by starting
- X with a non-alphanumeric or upper-case character.
- X Label must start in col 1 if it exists.
- X*/
- Xint process ()
- X{
- X char *ipt;
- X int i, done;
- X static char *zit = "";
- X
- X pass ++;
- X lineno[0] = 0;
- Xcontproc:
- X while (fgets (buf, LINEBUFLEN, input[currinput]) != NULL) {
- X (void) strcpy (linecopy, buf);
- X linecopy[strlen(linecopy)-1] = 0;
- X if (pass == 1) fputs (buf, output);
- X lineno[currinput]++;
- X ipt = buf;
- X label = ipt;
- X op = opd = optop = zit;
- X while (islabel (*ipt)) ipt++;
- X if (iseol (*ipt))
- X goto shortline;
- X *ipt++ = 0;
- X while (iswhite (*ipt)) ipt++;
- X if (iseol (*ipt)) {
- Xshortline: if (pass == 2)
- X listit (linecopy, lc, dummy, 0);
- X continue;
- X }
- X op = ipt;
- X while (isalnum (*ipt)) ipt++;
- X if (iseol (*ipt)) {
- X *ipt = 0;
- X goto parsed;
- X }
- X if (!iswhite(*ipt) && islower(*ipt))
- X (void) strcpy ((optop = malloc (strlen (ipt) + 1)), ipt);
- X *ipt++ = 0;
- X while (iswhite (*ipt)) ipt++;
- X opd = ipt;
- X while (*ipt != '\n') ipt++;
- X *ipt = 0;
- Xparsed:
- X if ((i = opsrch (op, pseudotab, pseudolen)) >= 0) {
- X done = (pseudotab[i].action) ();
- X } else if ((i = opsrch (op, optab, instrlen)) >= 0) {
- X (void) (optab[i].action) (i);
- X } else {
- X reporterr (E_ILLOP);
- X listit (linecopy, lc, dummy, 0);
- X }
- X if (done) break;
- X }
- X if (!end_found) {
- X do_end();
- X reporterr (E_NOEND);
- X }
- X if (currinput > 0) {
- X free (filename[currinput]);
- X filename[currinput] = NULL;
- X (void) fclose (input[currinput--]);
- X goto contproc;
- X }
- X return (errorstat);
- X}
- X
- Xint opsrch (op, table, hi)
- X char *op;
- X opdef table[];
- X int hi;
- X{
- X int lo, mid, i;
- X
- X/* Binary search - assumes that list extends from optab[0] through
- X optab[hi-2] inclusive. The hi and lo indicies always point to
- X ruled out table locations plus 1, to keep away from rounding
- X problems on the far side of zero. Whenever they come to within 1
- X of each other, the jig is up (and gone......)
- X*/
- X
- X lo = 0;
- X while (1) {
- X mid = (hi + lo) / 2;
- X if ((i = strcmp (table[mid - 1].name, op)) == 0)
- X return (--mid);
- X else if (i > 0)
- X hi = mid;
- X else
- X lo = mid;
- X if (hi - lo <= 1) break;
- X }
- X return (-1);
- X}
- X
- X
- Xvoid listit (line, xlc, binbuf, length)
- X char *line;
- X Memad xlc;
- X Word binbuf[];
- X int length;
- X{
- X int addit, i;
- X
- X addit = 0;
- X do {
- X listint (line, xlc + addit, &binbuf[addit], length - addit);
- X addit += listlen;
- X line = (char *)0;
- X } while (addit < length);
- X return;
- X}
- X
- X
- Xvoid listint (line, xlc, binbuf, length)
- X char *line;
- X Memad xlc;
- X Word *binbuf;
- X int length;
- X{
- X int i;
- X
- X if (listing && liston) {
- X (void) fprintf (list, "%4ld %08x: ", lineno[currinput], xlc);
- X if (length > listlen) length = listlen;
- X for (i = 0; i < length; i++)
- X (void) fprintf (list, "%02x ", binbuf[i]);
- X for (; i < listlen; i++)
- X (void) fprintf (list, " ");
- X /* move up to an 8 byte (tab) boundary */
- X for (i = 0; i < (81-3*listlen)%8; i++)
- X (void) fprintf (list, " ");
- X if (line) (void) fprintf (list, "%s", line);
- X (void) fprintf (list, "\n");
- X }
- X return;
- X}
- X
- X
- X/* Binary output format:
- X
- X Intel standard hexadecimal format!!!!
- X
- X Output is a series of variable length records consisting of ascii
- X characters 0-9, A-F (0x30-0x39, 0x41-0x6). Each character contains
- X four bits of significant data; two such characters form a binary
- X byte of data, the binary equivalent to the hexadecimal ascii
- X characters.
- X
- X The data records have the format:
- X
- X / len covers this \
- X +---+---+---+---+---+---+---+---+---+--------//--------+---+---+
- X | : | len | address | 0 | 0 | data bytes | cksum |
- X +---+---+---+---+---+---+---+---+---+--------//--------+---+---+
- X \ checksum covers this /
- X
- X Checksum computed such that sum of all bytes except ':' modulo
- X the bytelength is 0.
- X
- X End Record:
- X
- X +---+---+---+---+---+---+---+---+---+---+---+
- X | : | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | f | f |
- X +---+---+---+---+---+---+---+---+---+---+---+
- X
- X
- X*/
- Xvoid putoutbin (binbuf, length)
- X Word binbuf[];
- X int length;
- X{
- X static Memad address;
- X static int count;
- X static Word checksum;
- X static Word array[BINBUFLEN];
- X static Word *curpt = 0;
- X static Memad binlc = ~0;
- X int i;
- X
- X if (binlc != lc) {
- X if (curpt != 0) {
- X (void) fwrite (":", 1, 1, output);
- X putout ((Word) count);
- X putout ((Word) (address >> 8));
- X putout ((Word) (address & 0xff));
- X (void) fwrite ("00", 2, 1, output);
- X for (i = 0; i < count; i++)
- X putout (array[i]);
- X checksum += (count & 0xff) +
- X (address >> 8) +
- X (address & 0xff);
- X putout (-checksum);
- X if (length == 0) {
- X (void) fwrite (":00000001ff", 11, 1, output);
- X }
- X }
- X curpt = array;
- X count = 0;
- X address = binlc = lc;
- X checksum = 0;
- X }
- X for (i = 0; i < length; i++) {
- X *curpt++ = binbuf[i];
- X checksum += binbuf[i];
- X count++;
- X binlc ++;
- X }
- X if (count > BINBUFLEN - MAXBYTPERINS)
- X binlc = 0;
- X return;
- X}
- X
- X#define hex(x) x+(x<10?'0':'7')
- X
- Xvoid putout (c)
- X Word c;
- X{
- X Word outc[2], t;
- X
- X t = c>>4;
- X c &= 0xf;
- X outc[0] = hex(t);
- X outc[1] = hex(c);
- X (void) fwrite ((char *)outc, 2, 1, output);
- X return;
- X}
- X
- X
- Xvoid insert (name, value, type, segment, mult)
- X char *name;
- X long value;
- X opdclass *type;
- X segmnt *segment;
- X int mult;
- X{
- X int x, y;
- X symbol *sp;
- X
- X x = y = hash (name);
- X while ((sp = &symtab[x])->name != (char *) 0) {
- X if (strcmp (sp->name, name) == 0) {
- X if (!mult && value != sp->value && pass == 1) {
- X reporterr (E_MULT);
- X return;
- X }
- X break;
- X }
- X if (++x == y) reporterr (E_STOFLO);
- X if (x == NSYMS) x = 0;
- X }
- X sp->name = malloc ((unsigned) strlen (name) + 1);
- X (void) strcpy (sp->name, name);
- X sp->value = value;
- X sp->type = type;
- X sp->segp = segment;
- X return;
- X}
- X
- X
- Xint lookup (name)
- X char *name;
- X{
- X int x, y;
- X
- X x = y = hash (name);
- X while (symtab[x].name != (char *) 0) {
- X if (strcmp (name, symtab[x].name) == 0)
- X return (x);
- X x++;
- X if (x == y) return (-1);
- X if (x == NSYMS) x = 0;
- X }
- X return (-1);
- X}
- X
- X
- Xint hash (string)
- X char *string;
- X{
- X char *pt;
- X int tot;
- X
- X tot = 0;
- X for (pt = string; *pt; pt++)
- X tot += *pt;
- X if (NSYMS >= 256)
- X tot += (tot << 8);
- X return (tot % NSYMS);
- X}
- X
- X
- Xvoid reporterr (errcode)
- X int errcode;
- X{
- X static char *elist[] = {
- X "",
- X "aborting at end of pass1",
- X "aborting at end of pass2",
- X "symbol table overflow",
- X "input file error",
- X "too many nested includes",
- X "include syntax error",
- X "illegal expression",
- X "undefined symbol",
- X "unknown op code",
- X "multiply defined symbol",
- X "insufficient operands",
- X "value too large for field",
- X "unsigned value negative",
- X "segment violation",
- X "opcode suffix syntax",
- X "no end statement - simulated",
- X };
- X
- X if (pass == 1) {
- X if (list)
- X (void) fprintf (list, "----> Error in file %s, line %d: %s\n", filename[currinput], lineno[currinput], elist[errcode]);
- X (void) fprintf (stderr, "----> Error in file %s, line %d: %s\n", filename[currinput], lineno[currinput], elist[errcode]);
- X } else {
- X if (list)
- X (void) fprintf (list, "----> %s: %s\n", filename[currinput], elist[errcode]);
- X (void) fprintf (stderr, "----> %s: %s\n", filename[currinput], elist[errcode]);
- X }
- X (void) fflush (list);
- X if (errcode <= A_MAX) {
- X (void) fprintf (stderr, "asm: Abort error: %s\n", elist[errcode]);
- X exit (1);
- X }
- X errorstat++;
- X return;
- X}
- X
- X
- Xvoid sort ()
- X{
- X char c;
- X
- X while ((c = getc (input[0])) > 0)
- X putc (c, output);
- X return;
- X}
- X
- X
- Xvoid crossref ()
- X{
- X int i, j, k, gap;
- X symbol symtemp;
- X
- X (void) fprintf (list, "\n\n\n Cross Reference\n\n");
- X k = 0;
- X for (i = 0; i < NSYMS; i++)
- X if (symtab[i].name && *symtab[i].name)
- X symtab[k++] = symtab[i];
- X for (gap = k / 2; gap > 0; gap /= 2)
- X for (i = gap; i < k; i++)
- X for (j = i - gap; j >= 0; j -= gap) {
- X if (strcmp (symtab[j].name,
- X symtab[j+gap].name) <= 0)
- X break;
- X symtemp = symtab[j];
- X symtab[j] = symtab[j+gap];
- X symtab[j+gap] = symtemp;
- X }
- X for (i = 0; i < k; i++)
- X (void) fprintf (list, " %s: 0x%x\n", symtab[i].name,
- X symtab[i].value);
- X return;
- X}
- @FUNKY STUFF~
- echo extracting - data.c
- sed 's/^X//' > data.c << '@FUNKY STUFF~'
- X#include "asm.h"
- X
- Xopdclass o_none = {0, 0, 0, 0};
- Xinsclass i_noopd = {1, 0, &o_none, &o_none, 0, 0};
- Xopdef pseudotab[] = {
- X "bss" , &i_noopd, 0x00, do_bss ,
- X "data" , &i_noopd, 0x00, do_data ,
- X "data2" , &i_noopd, 0x00, do_data2 ,
- X "end" , &i_noopd, 0x00, do_end ,
- X "equ" , &i_noopd, 0x00, do_equ ,
- X "include", &i_noopd, 0x00, do_incl ,
- X "listoff", &i_noopd, 0x00, do_loff ,
- X "liston" , &i_noopd, 0x00, do_lon ,
- X "org" , &i_noopd, 0x00, do_org ,
- X "seg" , &i_noopd, 0x00, do_seg ,
- X "set" , &i_noopd, 0x00, do_set ,
- X "string" , &i_noopd, 0x00, do_string,
- X "" , &i_noopd, 0x00, 0
- X};
- X
- XFILE *input[INCLSTACK], *output, *list = (FILE *)0, *srcin, *binout;
- Xchar *name, *label, *op, *opd, *optop;
- Xchar buf[LINEBUFLEN], linecopy[LINEBUFLEN], *filename[INCLSTACK];
- Xint lineno[INCLSTACK], ignerr, end_found;
- Xint errorstat=0, currinput=0, pass=0, liston=YES, listing=0, binary=0, xref=0;
- Xsymbol *symtab; Memad lc; Word *dummy;
- Xsegmnt segmain={0, 0, "", 0};
- Xsegmnt *seghd = &segmain, *curseg = &segmain, *exprseg;
- X
- X#include "ops.h"
- X
- Xint listlen = BYTESPERLINE;
- Xint pseudolen = sizeof (pseudotab) / sizeof (opdef);
- Xint instrlen = sizeof (optab) / sizeof (opdef);
- @FUNKY STUFF~
- echo extracting - instructions.c
- sed 's/^X//' > instructions.c << '@FUNKY STUFF~'
- X#include "asm.h"
- X
- Xint choiceinstr (ins)
- X int ins;
- X{
- X choicedef *chpt;
- X int num, i, fits;
- X Long value;
- X static char *opdpt;
- X
- X if (label && *label)
- X insert (label, (long) lc, &o_none, curseg, NO);
- X chpt = (choicedef *)optab[ins].class;
- X num = chpt->field;
- X for (opdpt = opd; num > 1; num --) {
- X opdpt = index (opdpt, ',');
- X if (opdpt == NULL) {
- X reporterr (E_NOPS);
- X return (0);
- X }
- X opdpt++;
- X }
- X value = expr (&opdpt, &i, YES);
- X fits = i ? NO :
- X (value >= chpt->lorange &&
- X value <= chpt->hirange &&
- X curseg == exprseg);
- X if ((i = opsrch ((fits ? chpt->rname : chpt->nname),
- X optab, instrlen)) >= 0) {
- X (optab[i].action) (i);
- X } else {
- X reporterr (E_ILLOP);
- X }
- X return (0);
- X}
- X
- X
- Xint geninstr (ins)
- X int ins;
- X{
- X static Acc cons = ~0L;
- X int nargs, length, i, j, k;
- X opdclass *oclass;
- X insclass *iclass;
- X Word itemtemp, obuf[MAXBYTPERINS];
- X Acc mask;
- X char *nextopd;
- X itemu item;
- X
- X if (label && *label)
- X insert (label, (long) lc, &o_none, curseg, NO);
- X iclass = optab[ins].class;
- X length = iclass->length;
- X if (pass == 2) {
- X nargs = iclass->mopds;
- X for (i = 0; i < MAXBYTPERINS; i++)
- X obuf[i] = 0;
- X item.l = optab[ins].mask;
- X for (i = 0; i < MINBYTES; i++)
- X obuf[i] = item.s[i];
- X item.l = 0L;
- X nextopd = opd;
- X for (j = 0; j < nargs; j++) {
- X if (j != 0) {
- X if (*nextopd != ',') {
- X reporterr (E_NOPS);
- X } else {
- X nextopd++;
- X }
- X }
- X oclass = iclass->type[j];
- X item.l = expr (&nextopd, &ignerr, NO) + oclass->offset -
- X (oclass->relative ? lc : 0);
- X mask = cons >> (LONGLEN - oclass->length);
- X if (item.l < 0L && !oclass->signed)
- X reporterr (E_NEG);
- X if (((item.ls < 0L && oclass->signed) ? -item.ls : item.ls) & ~mask)
- X reporterr (E_TOOBIG);
- X item.l &= mask;
- X if (oclass->byteswapped) {
- X itemtemp = item.s[BYTPERLONG - 2];
- X item.s[BYTPERLONG - 2] = item.s[BYTPERLONG - 1];
- X item.s[BYTPERLONG - 1] = itemtemp;
- X }
- X i = LONGLEN - 8 - iclass->offset[j];
- X item.l <<= (i % 8);
- X i /= 8;
- X k = 0;
- X if (i < 0)
- X k = -i, i = 0;
- X for (; k < MAXBYTPERINS && i < BYTPERLONG; k++, i++)
- X#ifdef NORMBYTE
- X obuf[k] |= item.s[i];
- X#else
- X obuf[k] |= item.s[BYTPERLONG-1-i];
- X#endif
- X }
- X if (optop) {
- X optional (optop, obuf);
- X free (optop);
- X }
- X putoutbin (obuf, length);
- X listit (linecopy, lc, obuf, length);
- X }
- X lc += length;
- X return (0);
- X}
- X
- Xlong expr (string, errind, test)
- X char **string;
- X int *errind;
- X int test;
- X{
- X long exp, val;
- X int op, err;
- X int uniop = 0;
- X segmnt *seg1, *seg2;
- X
- X *errind = NO;
- X if (**string == '-')
- X uniop = 1;
- X else if (**string == '~')
- X uniop = 2;
- X if (uniop)
- X (*string)++;
- X exp = getval(string, &err, test, &seg1);
- X if (err) goto errorexit;
- X if (uniop == 2)
- X exp = ~exp;
- X else if (uniop == 1)
- X exp = -exp;
- X while (!isdelim(**string)) {
- X if ((op = getop (string)) == NOOP) {
- X if (!test) reporterr (E_EXPR);
- Xerrorexit: for (; !isdelim (**string); *string++) ;
- X *errind = YES;
- X return (0);
- X }
- X val = getval (string, &err, test, &seg2);
- X if (err) goto errorexit;
- X if (seg1 && seg2 && seg1 != seg2 && pass == 1)
- X reporterr (E_SEG);
- X switch (op) {
- X case PLUS:
- X exp += val;
- X break;
- X case MINUS:
- X exp -= val;
- X break;
- X case MULT:
- X exp *= val;
- X break;
- X case DIV:
- X exp /= val;
- X break;
- X case MOD:
- X exp %= val;
- X break;
- X case OR:
- X exp |= val;
- X break;
- X case AND:
- X exp &= val;
- X break;
- X case EXOR:
- X exp ^= val;
- X break;
- X case SHLF:
- X exp <<= val;
- X break;
- X case SHRT:
- X exp >>= val;
- X break;
- X default:
- X if (!test) reporterr (E_EXPR);
- X }
- X seg1 = seg2;
- X }
- X exprseg = seg1;
- X return (exp);
- X}
- X
- X
- X/* Snag literals and variable names. The literal classes are:
- X
- X [digit]....[digit] unsigned decimal number
- X 0[hexdigit]...[hexdigit]unsigned hexadecimal number
- X $ current location counter
- X '[char] single character, right just, zero fill
- X "[char][char] character pair
- X
- X Returns a 16 bit value. Unary operations taken care of in expr;
- X byte swapping done if required by geninstr.
- X*/
- Xlong getval (strpt, errorret, test, segment)
- X segmnt **segment;
- X char **strpt;
- X int *errorret;
- X int test;
- X{
- X long total;
- X char name[33], *npt;
- X int i;
- X
- X *segment = (segmnt *) 0;
- X *errorret = 0;
- X total = 0L;
- X if (isdigit (**strpt)) {
- X if (**strpt == '0') {
- X while (isxdigit (**strpt)) {
- X total *= 16;
- X total += xtod (**strpt);
- X (*strpt)++;
- X }
- X } else {
- X while (isdigit (**strpt)) {
- X total *= 10;
- X total += (Long)(**strpt - '0');
- X (*strpt)++;
- X }
- X }
- X } else if (islabel (**strpt)) {
- X npt = name;
- X while (islabel (**strpt)) {
- X *npt++ = **strpt;
- X (*strpt)++;
- X }
- X *npt = '\0';
- X if ((i = lookup (name)) == -1) {
- X if (pass == 2)
- X if (!test) reporterr (E_UNDEF);
- X *errorret = 1;
- X total = 0L;
- X } else {
- X total = symtab[i].value;
- X if (pass == 2 && symtab[i].segp)
- X total += (symtab[i].segp)->start;
- X *segment = symtab[i].segp;
- X }
- X } else if (**strpt == '\'') {
- X (*strpt)++;
- X if (**strpt == '\\') {
- X (*strpt)++;
- X total = escape (strpt);
- X } else {
- X total = **strpt;
- X (*strpt)++;
- X }
- X } else if (**strpt == '"') {
- X (*strpt)++;
- X if (**strpt == '\\') {
- X (*strpt)++;
- X total = escape (strpt);
- X } else {
- X total = **strpt;
- X (*strpt)++;
- X }
- X total <<= 8;
- X if (**strpt == '\\') {
- X (*strpt)++;
- X total |= escape (strpt);
- X } else {
- X total |= **strpt;
- X (*strpt)++;
- X }
- X } else if (**strpt == '$') {
- X total = lc;
- X *segment = curseg;
- X (*strpt)++;
- X } else {
- X if (!test) reporterr (E_EXPR);
- X *errorret = 1;
- X }
- X return (total);
- X}
- X
- X
- Xchar escape (st)
- X char **st;
- X{
- X switch (*((*st)++)) {
- X case 'b':
- X return ('\b');
- X case 'n':
- X return ('\n');
- X case 'r':
- X return ('\r');
- X case '^':
- X return ('\033');
- X case 'f':
- X return ('\f');
- X case 't':
- X return ('\t');
- X case '?':
- X return ('\177');
- X case '\\':
- X return ('\\');
- X default:
- X (*st)--;
- X if (isxdigit (**st) && isxdigit (*(*st + 1))) {
- X *st += 2;
- X return (xtod (*(*st - 2)) << 4 | xtod (*(*st - 1)));
- X } else {
- X return (*(*st++));
- X }
- X }
- X}
- X
- X
- Xint xtod (c)
- X char c;
- X{
- X return ((int) c - (c > '9' ? (c > 'F' ? 'W' : '7') : '0'));
- X}
- X
- X
- Xint getop (string)
- X char **string;
- X{
- X static char ops[] = OPSTRING;
- X char *k;
- X
- X for (k = ops; *k; k++)
- X if (*k == **string) {
- X (*string)++;
- X return ((int) (k - ops));
- X }
- X (*string)++;
- X return (NOOP);
- X}
- @FUNKY STUFF~
- echo extracting - makeops.c
- sed 's/^X//' > makeops.c << '@FUNKY STUFF~'
- X#include <stdio.h>
- X#include <ctype.h>
- X
- X#define iswhite(x) (x)==' '||(x)=='\t'||(x)==','
- X#define skipword while(isalnum(*pt)||*pt=='_')pt++;
- X#define skipwhite while(iswhite(*pt))pt++;
- X
- Xstruct {
- X char *name, *str;
- X} entry[100];
- X
- Xint ep, entryn = 0;
- Xchar buf[140], hold[2048];
- Xchar *pt, *pt2, *name, *arg1, *arg2;
- X
- Xextern int strncmp(), strcmp();
- X
- Xmain ()
- X{
- X while (gets (buf) > 0) {
- X if (strncmp (buf, "beginpattern", 12) == 0) {
- X pt = buf;
- X skipword;
- X skipwhite;
- X entry[entryn].name = (char *) malloc (strlen (pt) + 1);
- X strcpy (entry[entryn].name, pt);
- X pt = hold;
- X while (gets (buf) > 0 && strncmp (buf, "endpattern", 10) != 0) {
- X strcpy (pt, buf);
- X pt += strlen (pt);
- X *pt++ = '\n';
- X }
- X *pt = '\0';
- X entry[entryn].str = (char *) malloc (strlen (hold) + 1);
- X strcpy (entry[entryn].str, hold);
- X entryn++;
- X } else if (strncmp (buf, "pattern", 7) == 0) {
- X pt = buf;
- X skipword;
- X skipwhite; name = pt; skipword; *pt++ = 0;
- X skipwhite; arg1 = pt; skipword; *pt++ = 0;
- X skipwhite; arg2 = pt; skipword; *pt = 0;
- X for (ep = 0; ep < entryn; ep++) {
- X if (strcmp (name, entry[ep].name) == 0) {
- X for (pt = entry[ep].str; *pt; pt++) {
- X if (*pt == '~') {
- X switch (*(++pt)) {
- X case '1':
- X pt2 = arg1;
- X goto argout;
- X case '2':
- X pt2 = arg2;
- X argout: while (*pt2) {
- X putchar (*pt2++);
- X }
- X break;
- X default:
- X putchar ('~');
- X putchar (*pt);
- X }
- X } else {
- X putchar (*pt);
- X }
- X }
- X goto nextch;
- X }
- X }
- X fprintf (stderr, "makeops: can't find macro %s\n", name);
- Xnextch: ;
- X } else {
- X puts (buf);
- X }
- X }
- X exit (0);
- X}
- @FUNKY STUFF~
- echo extracting - pseudos.c
- sed 's/^X//' > pseudos.c << '@FUNKY STUFF~'
- X#include "asm.h"
- X
- Xint do_incl ()
- X{
- X if (pass == 1) {
- X char *ip;
- X
- X if (++currinput > INCLSTACK)
- X reporterr (E_INCL);
- X opd++;
- X if ((ip = index (opd, '"')) == 0)
- X reporterr (E_INCLSYN);
- X *ip = 0;
- X if ((input[currinput] = fopen (opd, "r")) == NULL)
- X reporterr (E_INPUT);
- X filename[currinput] = strcpy (malloc ((unsigned) strlen (opd) + 1), opd);
- X lineno[currinput] = 0;
- X }
- X return (0);
- X}
- X
- X
- Xint do_org ()
- X{
- X if (label && *label)
- X insert (label, (long) lc, &o_none, curseg, NO);
- X if (pass == 2)
- X listit (linecopy, lc, dummy, 0);
- X lc = (Memad) expr (&opd, &ignerr, NO);
- X return (0);
- X}
- X
- X
- Xint do_loff ()
- X{
- X liston = NO;
- X return (0);
- X}
- X
- X
- Xint do_lon ()
- X{
- X liston = YES;
- X return (0);
- X}
- X
- X
- Xint do_equ ()
- X{
- X long eqtemp;
- X
- X eqtemp = expr (&opd, &ignerr, NO);
- X if (label && *label)
- X insert (label, eqtemp, &o_none, exprseg, NO);
- X if (pass == 2)
- X listit (linecopy, eqtemp, dummy, 0);
- X return (0);
- X}
- X
- X
- Xint do_seg ()
- X{
- X segmnt *sp, *osp;
- X
- X curseg->lc = lc;
- X if (opd && *opd) {
- X for (sp = seghd; sp; osp = sp, sp = sp->next) {
- X if (strcmp (sp->name, opd) == 0) {
- X lc = sp->lc;
- X curseg = sp;
- X goto fin_seg;
- X }
- X }
- X } else {
- X lc = seghd->lc;
- X curseg = seghd;
- X }
- X curseg = osp->next = (segmnt *) malloc ((unsigned) sizeof (segmnt));
- X curseg->name = strcpy (malloc ((unsigned) strlen (opd) + 1), opd);
- X curseg->lc = lc = 0;
- X curseg->next = (segmnt *) 0;
- Xfin_seg:
- X if (pass == 2)
- X listit (linecopy, lc, dummy, 0);
- X return (0);
- X}
- X
- X
- Xint do_set ()
- X{
- X long eqtemp;
- X
- X eqtemp = expr (&opd, &ignerr, NO);
- X if (label && *label)
- X insert (label, eqtemp, &o_none, exprseg, YES);
- X if (pass == 2)
- X listit (linecopy, eqtemp, dummy, 0);
- X return (0);
- X}
- X
- X
- Xint do_bss ()
- X{
- X if (label && *label)
- X insert (label, (long) lc, &o_none, curseg, NO);
- X if (pass == 2)
- X listit (linecopy, lc, dummy, 0);
- X lc += (Memad) expr (&opd, &ignerr, NO);
- X return (0);
- X}
- X
- X
- Xint do_end ()
- X{
- X end_found ++;
- X curseg->lc = lc;
- X if (pass == 2) {
- X listit (linecopy, lc, dummy, 0);
- X lc = 0xffff;
- X putoutbin (dummy, 0);
- X }
- X curseg = seghd;
- X return (1);
- X}
- X
- X
- Xint do_data ()
- X{
- X Word temp, templist[MAXBYTPERINS];
- X char *tp;
- X int count;
- X
- X if (label && *label)
- X insert (label, (long) lc, &o_none, curseg, NO);
- X tp = opd;
- X count = 1;
- X if (*opd == ':') {
- X ++opd;
- X count = expr (&opd, &ignerr, NO);
- X if (*opd == ':') {
- X opd ++;
- X } else {
- X reporterr (E_EXPR);
- X count = 1;
- X opd = tp;
- X }
- X }
- X if (pass == 2) {
- X int i, j;
- X
- X temp = (Word) expr (&opd, &ignerr, NO);
- X for (i = 0; i < MAXBYTPERINS; i++)
- X templist[i] = temp;
- X listit (linecopy, lc, templist, count);
- X for (i = 0; i < count; i++)
- X putoutbin (&temp, 1);
- X }
- X lc += count;
- X return (0);
- X}
- X
- X
- Xint do_data2 ()
- X{
- X Long temp;
- X char *tp;
- X int count;
- X
- X if (label && *label)
- X insert (label, (long) lc, &o_none, curseg, NO);
- X tp = opd;
- X count = 1;
- X if (*opd == ':') {
- X ++opd;
- X count = expr (&opd, &ignerr, NO);
- X if (*opd == ':') {
- X opd ++;
- X } else {
- X reporterr (E_EXPR);
- X count = 1;
- X opd = tp;
- X }
- X }
- X if (pass == 2) {
- X int i;
- X
- X temp = (Long) expr (&opd, &ignerr, NO);
- X listit (linecopy, lc, (Word *)&temp, 2*count);
- X for (i = 0; i < count; i++) {
- X putoutbin ((Word *)&temp, 1);
- X }
- X }
- X lc += (2 * count);
- X return (0);
- X}
- X
- X
- Xint do_string ()
- X{
- X Word buf[120], *bp;
- X Word delim;
- X int len, i;
- X
- X if (label && *label)
- X insert (label, (long) lc, &o_none, curseg, NO);
- X delim = *opd++;
- X bp = buf;
- X while (*opd != delim) {
- X if (*opd != '\\')
- X *bp++ = *opd;
- X else {
- X ++opd;
- X *bp++ = escape (&opd);
- X }
- X opd++;
- X }
- X *bp++ = '\0';
- X len = bp - buf;
- X if (pass == 2) {
- X listit (linecopy, lc, buf, len);
- X putoutbin (buf, len);
- X }
- X lc += len;
- X return (0);
- X}
- X
- X
- @FUNKY STUFF~
- echo extracting - asm.1
- sed 's/^X//' > asm.1 << '@FUNKY STUFF~'
- X.so /usr/lib/tmac/tmac.e
- X.TH ASM 1 "1 May 1986"
- X.SH NAME
- Xasm \- generic assembler
- X.SH SYNOPSIS
- X.B asm
- X[
- X.B \-o
- Xbinname] [
- X.B \-l
- Xlistname] [
- X.B \-x
- Xxrefname] inputfile
- X.br
- X.SH DESCRIPTION
- XThe generic assembler is an attempt to build a quick-and-dirty meta-
- Xassembler, with which code for several types of microcomputers can be
- Xgenerated. It outputs absolute code in two passes, contains a minimum of
- Xpseudo-ops, and is quasi-portable between micro types. The opcodes and
- Xinstruction layout information is contained within tables, leaving the
- Xcode unchanged from micro to micro. There has been no effort expended to
- Xmake the assembler match any particular assembly format on the market, so
- Xdon't expect any miracles there.
- X
- XThe statup options specify various files for input and output. The basic
- Xoption is the name of the input file; normally it is suffixed by ".a",
- Xalthough this is not necessary. If no file is given, then input is taken
- Xfrom standard input. The
- X.B \-o
- Xoption introduces the name of the file to receive the binary
- Xoutput. If the option does not exist, the binary goes to standard output
- X(since the output is actually in ASCII format, it won't bolix your screen
- Xif you forget). If the option is not followed immediately by a filename,
- Xthen the binary will be output to the input file name suffixed by ".o".
- XThe format of the binary output is "Intel Standard Hexadecimal Format" and
- Xis documented in the source code.
- XThe
- X.B \-l
- Xoption similarly specifies the file for the assembly listing; if the
- Xoption is not given, no listing is produced. If the option is alone, then
- Xthe listing will go into the input file name suffixed with ".l". The
- X.B \-x
- Xoption specifies the file to receive the cross-reference; it defaults to
- Xthe same filename as the listing, and is deleted if the option is not
- Xgiven.
- X.pp
- XThe assembler boasts (or at least admits) the following features:
- X.in +.5i
- X.ip \(bu
- XTwo pass, all labels are defined both forward and backward.
- X.ip \(bu
- XAbsolute format code only, no relocation information available.
- X.ip \(bu
- XTable driven instruction formats, including single opcodes and fixed
- Xnumbers of operands.
- X.ip \(bu
- XExpression evaluation in operands is left-to-right, no precedence or
- Xparentheses.
- X.ip \(bu
- XPredefined symbols accomodated.
- X.ip \(bu
- XInstructions formats that vary with the size of certain of their operands
- Xare accomodated, with some restrictions.
- X.ip \(bu
- XPseudo-ops include org, equ, set (for changing manifest variables), bss,
- Xdata, data2 (two bytes!!), string, seg (for setting up data segments that
- Xare made contiguous right after pass 1)
- Xand end.
- X.ip \(bu
- XAtoms in operands include labels, ops add (+), subtract (-), multiply (*),
- Xinteger divide (/), mod (%), and (&), or (|), and exclusive or (^),
- Xdecimal constants, hexadecimal constants (with a leading zero), right
- Xjustified zero-filled single characters ('x) and double characters ("xx).
- XThe string pseudo-op supports strings surrounded by any unused delimiter.
- X.in -.5i
- X.pp
- XThe pseudo op syntax is as follows:
- X.in +.5i
- X.ip "[label] org expr
- XSet the value of the symbol in label to the current location counter; set
- Xthe location counter to the value of the expression.
- X.ip "label equ expr
- XSet the value of the symbol in label to the value of the expression. Any
- Xsuch value may only be changed by a "set" pseudo.
- X.ip "label set expr
- XReset the value of a symbol to the value of the expression.
- X.ip "[label] bss expr
- XSet the value of the symbol in the label to the current location counter,
- Xthen set the location counter to its current value plus the value of the
- Xexpression.
- X.ip "[label] data [:count:]expr
- XSet the value of the label to the current location counter, and then
- Xgenerate count (default 1) bytes of data, each containing the value of the
- Xexpression. Count must contain no forward referenced symbols.
- X.ip "[label] data2 [:count:]expr
- XSet the value of the label to the current location counter, and then
- Xgenerate count (default 1) double-bytes of data, each double-byte
- Xcontaining the value of the expression.
- XCount must contain no forward referenced symbols.
- X.ip "[label] string $string$
- XSet the value of the label to the current location counter, and then
- Xgenerate the string as bytes from left to right, appending a single nul
- Xbyte. The string delimiter shown above ($) may be any character that
- Xdoesn't appear in the string itself, except blank or tab. The special
- Xescapes \\t (tab), \\r (carriage return), \\n (newline), \\b (backspace),
- X\\? (del), \\^ (escape), \\nn (nn is any hex pair) and \\\\ (\\ itself)
- Xare allowed.
- X.ip " seg [name]
- XDeclare a new or reuse an older data segment, which defines it's own
- Xlocation counter. The segment that is predefined at the beginning of the
- Xassembler may be returned to by a
- X.b seg
- Xwith no argument. Any number of segments may be invoked. Each segment's
- Xlocation counter starts at zero during pass 1. When pass 1 is complete,
- Xthe segments are "stacked" in the order that they were created, so that
- Xthe second segment's lc starts at the first location following the end of
- Xthe first segment's highest lc. These computed lc's are displayed in the
- Xpass 2 listing output. The name used may be any non-blank-containing
- Xstring; it is also independent of the symbol name space. At this time,
- Xthere are no other definable characteristics of segments.
- X.in -.5i
- X.SH "MACHINES SUPPORTED
- XWith this edition are included tables for the Motorola 6803 and 6809, the
- XIntel 8085 and 6502.
- X.SH "OTHER FILES
- X/tmp/asm* - intermediate files.
- X.SH AUTHOR
- XLyle McElhaney
- @FUNKY STUFF~
- echo extracting - asm_ops.5
- sed 's/^X//' > asm_ops.5 << '@FUNKY STUFF~'
- X.so /usr/lib/tmac/tmac.e
- X.TH ASM_OPS 5 "1 Nov 1986"
- X.SH NAME
- Xasm_ops \- generic assembler op-code tables
- X.SH DESCRIPTION
- XThe generic assembler
- X.b asm
- Xcan be made to assemble code for a number of different microprocessors. At
- Xthe time of this writing, codes have been developed for the Intel 8085,
- Xthe Motorola 6803, , the 6809 (with a lot of squeezing) and the 6502
- X(Commodore 64). This manual page will describe the format of the ops.h
- Xfile, which contains the processor-specific parts of the assembler. The
- Xstructures described below are defined in the file asm.h.
- X
- XThe opd.h file consists in a series of structure initializations, that
- Xgenerate tables in the assembler when it is compiled. Most of the lines
- Xare of the form:
- X
- X table-type name = {value, ....., value};
- X
- Xwhere the names are arbitrary (within the c-compiler naming restrictions)
- Xand the values may be integers, Flags (i.e., boolean-valued integers),
- Xstrings (actually pointers to strings), pointers to other structures
- Xwithin the file, and pointers to functions in the assembler itself. The
- Xtype Word refers an unsigned byte and Memad refers to a type holding any
- Xpossible memory address for the target machine. The type Acc refers to
- Xthe accumulator used in computing expression values; make it unsigned
- Xlong. If Acc is not 32 bits long, then some things will need changes,
- Xparticularly the mask field in the opdef structure.
- X
- XThe first structure is opdclass, which defines the kinds of operands that
- Xmay appear in an instruction, and their encoding in the corresponding
- Xinstruction word:
- X
- X.nf
- Xtypedef struct opdclassitem { /* This defines an instruction field */
- X int length; /* length in bits of field */
- X Flag signed; /* else unsigned */
- X Flag byteswapped; /* data has bytes backwards */
- X Flag relative; /* field is relative to $ */
- X int offset; /* fixed value added to field */
- X} opdclass;
- X.fi
- X
- XAn operand's
- X.b length
- Xrefers to the number of bits that are allocated for it
- Xin the instruction field. If that number is eight, then only numbers from
- X-128 through +127 (two's complement assumed) can fit in the field. If the
- Xnext flag,
- X.b signed ,
- Xis set then the range becomes 0 through 255, in this
- Xexample. The
- X.b byteswapped
- Xflag is set if the bytes (in a multibyte field)
- Xare to be loaded within a 2 byte word in right-to-left order, rather then
- Xthe more conventional left-to-right. The
- X.b relative
- Xflag is set if the value
- Xto be placed in the field must first be decremented by the value of the
- Xlocation counter before insertion. Finally,
- X.b offset
- Xis an integer value
- Xto be added to the value of the field before it is inserted. As an
- Xexample, an entry for the 6803 reads:
- X
- Xopdclass o_rmem = { 8, YES, NO , YES, -2};
- X
- XThis defines a field that is used in relative-mode instructions. The field
- Xis eight bits long, is signed, and is relative to the current lc. In
- Xaddition, it is expected to be decremented by two. Given all this, the
- Xlegal range of a value to be placed in this field must be from (lc)-126
- Xthrough (lc)+129 inclusive, where (lc) is the current value of the
- Xlocation counter (which points to the first byte of the current
- Xinstruction).
- X
- XThe second "set" of structures, insclass, define an instruction type.
- XEvery generated instruction must fall within one of these types. They
- Xdefine the instruction structure (as a collection of fields) and the
- Xwritten form of its invocation:
- X
- X.nf
- Xtypedef struct insclassitem { /* This defines an instruction type */
- X int length; /* instruction length in bytes */
- X int mopds; /* number of operands expected */
- X opdclass *type[MAXOPDS]; /* each operand's field type */
- X int offset[MAXOPDS]; /* each operand's bit offset,
- X from right end of first byte */
- X} insclass;
- X.fi
- X
- XThe
- X.b length
- Xof an instruction type is the number of bytes in the
- Xinstruction, including all the fields. The number of operands expected
- X.b mopd
- Xmay be 0, 1, or 2 (making this larger would involve changes to asm.h and
- Xasm.c). MAXOPDS enforces the current limit on operands to two. The
- Xmembers of the array
- X.btype
- Xare pointers to the appropriate opdclass defined
- Xabove. When the instruction is scanned, the first operand must fit the
- Xfield described in the structure pointed to be xxx.type[0], the second by
- Xxxx.type[1]. The array
- X.b offset
- Xdefines the amount of shifting to be done to
- Xproperly align the field in the instruction. An offset of zero states
- Xthat the field's rightmost bit should be placed in the rightmost bit of
- Xthe instruction's first byte; a negative offset requires the value to be
- Xshifted left that many bits, and a positive value must be shifted right.
- XAn example, again from the 6803, shows the format of a relative
- Xinstruction:
- X
- Xinsclass i_rel = {2, 1, &o_rmem, &o_none, 8, 0};
- X
- XSuch an instruction is two bytes long, and contains one operand. This
- Xoperand is a relative memory operand (from the example above), and it must
- Xbe shifted to the right 8 bits (which puts it in the second byte of the
- Xinstruction exactly). The second operand must have an address even though
- Xits not used; o_none fills this requirement.
- X
- XAll this is leading, of course to the definition of individual
- Xinstructions. These are defined in the opdef structures:
- X
- X.nf
- Xtypedef struct opdefitem { /* Defines an instruction */
- X char *name; /* instruction mnemonic */
- X insclass *class; /* instruction type */
- X Acc mask; /* mask for first byte of instruction */
- X int (*action) (); /* action routine for assembly */
- X} opdef;
- X.fi
- X
- XEach instruction has a
- X.b name
- Xthat is recognized during the source code
- Xscanning. It also has a pointer to the insclass
- X.b class
- Xthat defines both what the
- Xscanner should expect and how the finished instruction looks. The
- X.b mask
- Xis a value to be or'ed in with the assembled operand fields to complete the
- Xinstruction. It normally contains the instruction-unique bits known as the
- Xopcode. It is defined as an Acc type, and therefore the mask may exceed
- Xthe size of the instruction. Assume the most significant bits are aligned
- Xwhen assigning a value to
- X.b mask .
- XNote that this also limits the size of the mask (and the opcode-fixed bits of the
- Xinstruction) to the length of Acc. This is true of all fields in the
- Xinstruction; none may exceed the length of Acc in bits.
- X
- XFinally, the routine
- X.b action
- Xdefined to assemble the instruction
- Xmust be given. For all normal instructions, the routine is
- X.u geninstr ,
- Xwhich generates all normal instructions from the table data. This field is
- Xdefined primarily so that pseudo-ops can also use the structure.
- X
- XNow, the opdef table is defined in a slightly different way than the other
- Xtables. The entries in the other tables are all referenced by pointers,
- Xso their order is of no consequence. The opdef table (named optab), on
- Xthe other hand, must be searched by the assembler. Therefore, each entry
- Xis a member of the array optab, and not a separate statement. The entries
- Xin the table may be in no particular order, however, since the table is
- Xsearched linearly for the nonce.
- X
- XAn example of a defined instruction for the 6803 is
- X
- X.nf
- Xopdef optab [] =
- X ....
- X "bra" , &i_rel , 0x20000000, geninstr,
- X ....
- X};
- X.fi
- X
- XThe unconditional branch instruction has its format defined by the i_rel
- Xclass of instruction formats (which, as shown above, defines a two byte
- Xinstruction with one operand, etc.). The mask for the first byte of the
- Xinstruction (the opcode for a branch) is hex 20. It is generated by the
- Xgeninstr routine. Note that the
- X.b mask
- Xfield is assumed to be 32 bits long, in this instance.
- X
- XWhat of the microprocessors that have two different instructions that may
- Xbe used to perform an operation, such as the 6803 that can load a register
- Xfrom a memory location with either a two byte relative instruction or a
- Xthree byte extended instruction? The native assembler can generate the
- Xshortest instruction that will fulfill the effect; so can the generic
- Xassembler, under some circumstances. The third set of structures, called
- Xchoicedef, is used in this case:
- X
- X.nf
- Xtypedef struct chcitem { /* Defines the alternatives for instr choices */
- X char *rname; /* restrictive mnemonic */
- X char *nname; /* non-restrictive mnemonic */
- X int field; /* operand that is restricted */
- X int lorange, hirange; /* range of restriction inclusive */
- X Flag relative; /* to current lc, else absolute value */
- X} choicedef;
- X.fi
- X
- XAny choicedef that exists (there may be none, if the microprocessor has no
- Xsuch overlapping instructions) describes the tradeoff to be made. The
- X.b rname
- Xis the mnemonic that may be used in the restrictive case of the
- Xchoice (i.e., the one that is more desireable, usually leading to a
- Xsmaller instruction).
- X.b Nname
- Xis the mnemonic to be used otherwise.
- XPresumably, the two choices are mutually inclusive of all possibilities,
- Xso that the nname mnemonic may be substituted in all cases to achieve the
- Xdesired result. The field
- X.b field
- Xis either one or two, describing which
- Xfield the choice hinges on. The
- X.b lorange and
- X.b hirange
- Xvalues are the
- Xinclusive limits of the values that the field must fall within in order to
- Xqualify for the restrictive choice. Finally, the
- X.b relative
- Xflag states that
- Xthe ranges are or are not relative to the current location counter. (At
- Xthis point, the relative flag is not implemented.)
- X
- XThe infamous example:
- X
- X "add" , (insclass *)&c_add, 0x00, choiceinstr,
- X
- XThis entry in the optab table defines an pseudo instruction called add. It
- Xmay be expanded as the instruction adds, if conditions are right, or as
- Xaddz in any case. Instead of pointing to an instruction class, the second
- Xentry in the structure is the address of a choice structure, which is cast
- Xas an insclass pointer to keep c and lint happy. The mask is defaulted
- X(its value is not used), and the generating routine is changed to
- Xchoiceinstr, which handles the cases. The choicedef entry pointed to is:
- X
- Xchoicedef c_add = {"adds" , "addz" , 2, 0, 0xff, NO};
- X
- XThis defines a choice of either the adds instruction or the addz
- Xinstruction to add a memory location to an accumulator. The second field,
- Xthe memory reference, is the key: if the reference is greater than or equal
- Xto zero, and less than or equal to hex ff (decimal 255), then adds can be
- Xused; otherwise only addz is allowed.
- X
- XAs I said above, the choice mechanism is restricted in the decisions that
- Xit can make in attempting to use the shortest instruction. Since the
- Xchoices are all made during the first pass, the expression in the deciding
- Xfield must be completely backward-defined. That means that all symbols in the
- Xexpression must be either constants, be predefined (see below) or have
- Xbeen defined in the code physically before the line where the choice
- Xresides. In addition, all symbols in the expression must be in the same
- Xsegment as the code being generated. This is not to say that using a
- Xchoice instruction containing a forward reference is an error; rather, the
- Xassembler, in the absence of required data to make the decision, will opt
- Xfor the "otherwise" form of the instruction, when it could be possible to
- Xuse the other. As Captain Kirk says, "Sie la vie."
- X
- XThe last set of entries in the ops.h file is a group of predefined symbols
- Xthat the assembler "knows" about for all assemblies on this
- Xmicroprocessor. An example of these definitions is:
- X
- X.nf
- Xsymbol predef[] = {
- X {"ra" , 0x0, &o_reg , (struct seg *)0 },
- X {"rb" , 0x1, &o_reg , (struct seg *)0 },
- X {"eq" , 0x7, &o_cond , (struct seg *)0 },
- X {"nc" , 0x4, &o_cond , (struct seg *)0 },
- X {"" , 0x0, &o_none , (struct seg *)0 },
- X};
- X.fi
- X
- XThese predefine the symbols ra, rb, eq, and nc for use in instructions
- Xthat reference register a, register b, and the branch conditions eq and nc
- X(no carry). Each is given a value, points to an operand type (which is not
- Xcurrently used), and defined in the null segment (that is, the only
- Xpredefined, default segment). Note the null entry at the end of the table.
- X
- XAfter all the tables a routine called "optional" must be defined. Optional
- Xgets called whenever some non-lowercase or non-alphanumeric character is
- Xencountered in the opcode field. when this happens, collection of the
- Xopcode is terminated. After the rest of the instruction is fully encoded,
- Xoptional gets called as:
- X
- X optional (optop, obuf);
- X
- Xwhere optop is the string of characters that follow the opcode, and obuf is
- Xan array of Words that contains the binary result of the instruction
- Xassembly. Optional should modify obuf to achieve whatever results may be
- Xdeemed necessary. If there are no requirements for changing the
- Xinstruction at this point, then a null optional can be used:
- X
- X optional (optop, obuf) Word *obuf; char *optop; {}
- X
- XNow, given the above description it should be possible to define an ops.h
- Xfile to generate an assembler for most any machine. This scheme should
- Xwork for almost any 8 or 16 bit microprocessor, although its only been
- Xused with eights. Restrictions are enforced by the use of a long
- Xvariable for expression solution and for instruction compilation, and
- Xprobably other things that will become apparant when the assembler is
- Xported to some wierd machine.
- X
- XChoices for instruction format are arbitrary, of course. I use a branch
- Xconditional instruction with the conditional code as an operand to reduce
- Xthe size of the optab (simply laziness); it would be easy to have
- Xindividual branch instructions instead.
- X
- XFor the truely adventurous, I have put together a very simple macro
- Xprocessor to ease the pain of putting together tables for the more
- Xcomplicated machines. The 6809, for example, has many instructions that
- Xare of identical format, the only differences being in the constant mask
- Xpart of the op definition. (On the 6809, the memory reference instructions
- Xadd, adc, bit, sub, cmp, and so on; the various forms of the cmpy and cmpu
- Xinstructions form another similar group.) A pattern may be declared in the
- XXXXX_ops.h file in the form:
- X
- X beginpattern name
- X line......
- X another line...
- X endpattern
- X
- XThe lines in the pattern are invoked by the statement
- X
- X pattern name,arg1,arg2
- X
- XThe strings arg1 and arg2 are substituted directly into the lines to
- Xreplace the strings ~1 and ~2, respectively. That's all there is. Very
- Xsimple, really. Look at 6809_ops.h for examples.
- X
- XExpansion of the macros is done by the program makeops.c. Making the
- Xassembler, using the supplied makefile, will also build makeops, and
- Xfilter XXXX_ops.h through it to get ops.h, which is included in the
- Xcompilation of data.c.
- @FUNKY STUFF~
-