home *** CD-ROM | disk | FTP | other *** search
- Subject: v07i097: Generic assembler for micros, Part01/02
- Newsgroups: mod.sources
- Approved: mirror!rs
-
- Submitted by: seismo!cisden!lmc
- Mod.sources: Volume 7, Issue 97
- Archive-name: micro.asm/Part01
-
- Yet another assembler.......
-
- This one is for assembling absolute code (for prom loading, fer instance)
- for 8 and 16 bit microprocessors. I've used it successfully as a back-end
- for the small c compiler posted previously, and it works just fine, as
- long as you don't need any external subroutines loaded later on. Lints
- out as much as possible, but there are probably still some few errors
- within, particularly for 16 bit uPs. Feedback welcome. Also any newly
- generated machine tables.
-
- Shouldn't be too hard to add relocation stuff - I just didn't have that
- need.
-
- : This is a shar archieve. Extract with sh, not csh.
- : The rest of this file will extract:
- : 6803reg.h Makefile README asm.1 asm.c asm.h asm_ops.5
- echo extracting - 6803reg.h
- sed 's/^X//' > 6803reg.h << '-FUNKY STUFF~'
- X
- X; control register & bit definition
- X; assumes operating mode 2 or 3
- X
- Xp1ddr equ 0 ; port 1 data direction
- Xp2ddr equ 01 ; port 2 data direction
- Xp1dr equ 02 ; port 1 data
- Xp2dr equ 03 ; port 2 data
- X
- Xp2d_pc2 equ 080
- Xp2d_pc1 equ 040
- Xp2d_pc0 equ 020
- Xp2d_p24 equ 010
- Xscixmt equ p2d_p24
- Xp2d_p23 equ 08
- Xscircv equ p2d_p23
- Xp2d_p22 equ 04
- Xsciclock equ p2d_p22
- Xp2d_p21 equ 02
- Xtimerout equ p2d_p21
- Xp2d_p20 equ 01
- Xtimerin equ p2d_p20
- X
- Xtcsr equ 08 ; timer control & status
- X
- Xtcs_icf equ 080 ; input capture flag
- Xtcs_ocf equ 040 ; output capture flag
- Xtcs_tof equ 020 ; timer overflow flag
- Xtcs_eici equ 010 ; enable input capture interrupt
- Xtcs_eoci equ 08 ; enable output capture flag
- Xtcs_etoi equ 04 ; enable timer overflow interrupt
- Xtcs_iedg equ 02 ; input edge
- Xtcs_olvl equ 01 ; output level
- X
- Xcounth equ 09 ; timer counter msb
- Xcountl equ 0a ; timer counter lsb
- Xoutcmh equ 0b ; timer output compare msb
- Xoutcml equ 0c ; timer output compare lsb
- Xincaph equ 0d ; input capture msb
- Xincapl equ 0e ; input capture lsb
- Xrmcr equ 010 ; SCI rate & mode control
- X
- Xrmc_cc1 equ 08
- Xrmc_cc0 equ 04
- Xrmc_cc equ 0c ; clock source and format
- Xrmc_ss1 equ 02
- Xrmc_ss0 equ 01
- Xrmc_ss equ 03 ; clock speed select 0-3, hi-lo
- X
- Xtrcsr equ 011 ; xmit/rcv control & status
- X
- Xtrc_rdf equ 080 ; rcv data reg full
- Xtrc_ofe equ 040 ; overrun or framing error
- Xtrc_tre equ 020 ; xmit data reg empty
- Xtrc_rie equ 010 ; rcv interrupt enable
- Xtrc_re equ 08 ; receiver enable
- Xtrc_tie equ 04 ; xmit interrupt enable
- Xtrc_te equ 02 ; transmitter enable
- Xtrc_wu equ 01 ; wakeup
- X
- Xscirdr equ 012 ; SCI rcv data
- Xscitdr equ 013 ; SCI xmit data
- Xramcr equ 014 ; RAM control
- X
- Xram_sb equ 080 ; stand-by power
- Xram_e equ 040 ; internal RAM enabled
- X
- Xstintram equ 080
- Xenintram equ 0ff
- X
- X; interrupt vectors
- X
- Xvectors equ 0ff0
- Xscivec equ vectors+0
- Xtofvec equ vectors+02
- Xtocvec equ vectors+04
- Xticvec equ vectors+06
- Xrq1vec equ vectors+08
- Xswivec equ vectors+0a
- Xnmivec equ vectors+0c
- Xstartvec equ vectors+0e
- -FUNKY STUFF~
- echo extracting - Makefile
- sed 's/^X//' > Makefile << '-FUNKY STUFF~'
- XCFLAGS=-O
- X
- Xasm: asm.o
- X cc asm.o -o asm
- X
- Xasm.o: asm.h ops.h
- X
- Xclean:
- X rm -f asm *.o
- -FUNKY STUFF~
- echo extracting - README
- sed 's/^X//' > README << '-FUNKY STUFF~'
- XSimplicity itself: just link one of the XXXX_ops.h files to ops.h,
- Xand say make. You've got an assembler.
- 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 Contel, Inc.
- X 1101 W. Mineral Ave.
- X Littleton, CO 80120
- -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
- 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 "OTHER FILES
- X/tmp/asm* - intermediate files.
- X.SH AUTHOR
- XLyle McElhaney
- -FUNKY STUFF~
- echo extracting - asm.c
- sed 's/^X//' > asm.c << '-FUNKY STUFF~'
- X#include <stdio.h>
- X
- 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};
- X#include "ops.h"
- X
- X#define pseudolen sizeof(pseudotab)/sizeof(opdef)
- X
- XFILE *input[INCLSTACK], *output, *list;
- XFILE *srcin, *binout;
- X
- Xint errorstat = 0;
- Xchar *name;
- Xchar *label, *op, *opd;
- Xchar buf[100], linecopy[100];
- Xchar *filename[INCLSTACK];
- Xint lineno[INCLSTACK];
- Xint currinput = 0;
- Xint pass = 0;
- Xint liston = YES;
- Xint listing = 0;
- Xint binary = 0;
- Xint xref = 0;
- Xint ignerr;
- Xsymbol *symtab;
- XMemad lc;
- XWord *dummy;
- Xsegmnt segmain = {0, 0, "", 0};
- Xsegmnt *seghd = &segmain;
- Xsegmnt *curseg = &segmain;
- Xsegmnt *exprseg;
- 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 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 = 0;
- X return;
- X}
- X
- X
- X
- X/* Gross syntax rules: <and the rest of us simply obey>
- X Input line: [label] op [operands]
- X Comments: Blank lines and anything following ';'
- X White space is any combination of blank and/or tab chars.
- X Operands cannot contain white space (except within strings)
- X and are separated by commas.
- 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, sizeof buf, 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 = zit;
- X while (islabel (*ipt)) ipt++;
- X if (iseol (*ipt)) {
- X if (pass == 2)
- X listit (linecopy, lc, dummy, 0);
- X continue;
- X }
- X *ipt++ = 0;
- X while (iswhite (*ipt)) ipt++;
- X if (iseol (*ipt)) {
- X 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 *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, oplen)) >= 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 (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, tablen)
- X char *op;
- X int tablen;
- X opdef table[];
- X{
- X int i;
- X
- X for (i = 0; i < tablen; i++)
- X if (strcmp (table[i].name, op) == 0)
- X return (i);
- X return (-1);
- X}
- X
- 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_mem, 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_mem, 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_mem, 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_mem, 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 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_mem, 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 for (i = count; i > 0; i -= 3) {
- X j = i > MAXBYTPERINS ? MAXBYTPERINS : i;
- X listit (linecopy, lc, templist, j);
- X lc += j;
- X *linecopy = 0;
- X }
- X for (i = 0; i < count; i++)
- X putoutbin (&temp, 1);
- X } else
- 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_mem, 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 = expr (&opd, &ignerr, NO);
- X for (i = 0; i < count; i++) {
- X listit (linecopy, lc, (Word *)&temp, 2);
- X lc += 2;
- X *linecopy = 0;
- X putoutbin ((Word *)&temp, 1);
- X }
- X } else
- X lc += (count * 2);
- 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_mem, 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 for (bp = buf, i = 0; i < len; i += 3, bp += 3) {
- X listit (linecopy, lc + i, bp, len + buf - bp);
- X *linecopy = 0;
- X }
- X putoutbin (buf, len);
- X }
- X lc += len;
- X return (0);
- X}
- X
- 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_mem, 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), optab, oplen)) >= 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 int nargs, length, i, j, k;
- X opdclass *oclass;
- X insclass *iclass;
- X Word itemtemp, obuf[MAXBYTPERINS];
- X unsigned long mask;
- X static unsigned long cons = ~0L;
- X union itemitem {
- X Word s[BYTPERLONG];
- X unsigned long l;
- X long ls;
- X } item;
- X char *nextopd;
- X
- X if (label && *label)
- X insert (label, (long) lc, &o_mem, curseg, NO);
- X iclass = optab[ins].class;
- X length = iclass->length;
- X if (pass == 2) {
- X nargs = iclass->mopds;
- X item.l = 0L;
- X for (i = 0; i < MAXBYTPERINS; i++)
- X obuf[i] = 0;
- X *obuf = optab[ins].mask;
- 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 item.l <<= (LONGLEN - 8 - iclass->offset[j]);
- X for (k = 0; k < MAXBYTPERINS; k++)
- X obuf[k] |= item.s[k];
- 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}
- X
- X
- Xvoid listit (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 %04x: ", lineno[currinput], xlc);
- X if (length > 3) length = 3;
- X for (i = 0; i < length; i++)
- X (void) fprintf (list, "%02x ", binbuf[i]);
- X for (i = length; i < MAXBYTPERINS; i++)
- X (void) fprintf (list, " ");
- X (void) fprintf (list, " %s\n", line);
- 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 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 };
- X
- X if (pass == 1) {
- 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 (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 - asm.h
- sed 's/^X//' > asm.h << '-FUNKY STUFF~'
- X#include <ctype.h>
- X#define YES 1
- X#define NO 0
- X
- X#define NSYMS 253
- X#define INCLSTACK 10
- X#define MAXBYTPERINS 3
- X#define BYTPERLONG 4
- X#define LONGLEN 32
- X#define MAXOPDS 2
- X#define NHEAD 5 /* words of overhead in binary header */
- X#define BINBUFLEN 250
- X
- X#define iswhite(c) (c==' '||c=='\t')
- X#define iseol(c) (c=='\0'||c==';'||c=='\n')
- X#define isdelim(c) (c==','||c==':'||iseol(c)||iswhite(c))
- X#define islabel(c) (isalnum(c)||c=='_')
- X
- X#define A_MAX 6 /* highest error code causing immediate abort */
- X#define E_PASS1 1
- X#define E_PASS2 2
- X#define E_STOFLO 3
- X#define E_INPUT 4
- X#define E_INCL 5
- X#define E_INCLSYN 6
- X#define E_EXPR 7
- X#define E_UNDEF 8
- X#define E_ILLOP 9
- X#define E_MULT 10
- X#define E_NOPS 11
- X#define E_TOOBIG 12
- X#define E_NEG 13
- X#define E_SEG 14
- X
- X#define NOOP -1
- X#define PLUS 0
- X#define MINUS 1
- X#define MULT 2
- X#define DIV 3
- X#define MOD 4
- X#define OR 5
- X#define AND 6
- X#define EXOR 7
- X#define SHLF 8
- X#define SHRT 9
- X#define OPSTRING "+-*/%|&^<>" /* same order as definitions above */
- X
- Xtypedef unsigned char Word; /* instruction word */
- Xtypedef short Long; /* Long, that is, on an 8085: 16 bit data */
- Xtypedef char Short; /* 8 bit data */
- Xtypedef unsigned Long Memad;
- Xtypedef char Flag;
- X
- 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
- 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
- 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
- Xtypedef struct opdefitem { /* Defines an instruction */
- X char *name; /* instruction mnemonic */
- X insclass *class; /* instruction type */
- X Word mask; /* mask for first byte of instruction */
- X int (*action) (); /* action routine for assembly */
- X} opdef;
- X
- Xtypedef struct seg { /* Defines a location counter segment */
- X Memad lc, start; /* segment's lc and starting loc */
- X char *name; /* segment name */
- X struct seg *next; /* pointer to next segment */
- X} segmnt;
- X
- Xtypedef struct ltitem { /* Defines a label table entry */
- X char *name; /* symbol name */
- X long value; /* symbol's current value */
- X opdclass *type; /* symbol type (defines fields it can fill) */
- X segmnt *segp; /* pointer to segment value's defined in */
- X} symbol;
- X
- Xextern char *malloc();
- Xextern char *strcpy();
- Xextern char *strcat();
- Xextern char *mktemp();
- Xextern char *index();
- Xextern int geninstr();
- Xextern int choiceinstr();
- Xextern int do_bss();
- Xextern int do_data();
- Xextern int do_data2();
- Xextern int do_end();
- Xextern int do_equ();
- Xextern int do_seg();
- Xextern int do_set();
- Xextern int do_org();
- Xextern int do_string();
- Xextern int do_incl();
- Xextern int do_loff();
- Xextern int do_lon();
- Xextern void getargs ();
- Xextern void init ();
- Xextern void init2 ();
- Xextern int process ();
- Xextern void listit ();
- Xextern void insert ();
- Xextern void reporterr ();
- Xextern int hash ();
- Xextern long expr ();
- Xextern int getop ();
- Xextern long getval ();
- Xextern int lookup ();
- Xextern void putoutbin ();
- Xextern void crossref ();
- Xextern void sort ();
- Xextern void putout ();
- Xextern int xtod ();
- Xextern char escape ();
- -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, and the 6502 (Commodore 64). This manual page will
- Xdescribe the format of the ops.h file, which contains the processor-specific
- Xparts of the assembler. The structures described below are defined in the
- Xfile asm.h.
- X
- XThe opd.h file consists in a series of structure initializations, that
- Xgenerate tables in the assembler when it is compiled. All lines are of the
- Xform:
- 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.
- 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 6805 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 6805, 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 Word 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. Finally, 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. In addition,
- Xthe entries are all arranged in alphabetical order by
- X.b name .
- X
- XAn example of a defined instruction for the 6803 is
- X
- X.nf
- Xopdef optab [] =
- X ....
- X "bra" , &i_rel , 0x20, 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.
- X
- XFollowing the definition of optab is the statement
- X
- X#define oplen sizeof(optab)/sizeof(opdef)
- X
- Xwhich reveals the size of the optab to asm.c.
- 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 staes 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
- 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
- XSo it goes.
- -FUNKY STUFF~
-
-