home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume9 / assem2 / part01 next >
Text File  |  1987-03-11  |  49KB  |  1,744 lines

  1. Subject:  v09i026:  Generic assembler for micro's, Part01/02
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: cisden!lmc (Lyle McElhaney)
  6. Mod.sources: Volume 9, Issue 26
  7. Archive-name: assem2/Part01
  8.  
  9. echo extracting - README
  10. sed 's/^X//' > README << '@FUNKY STUFF~'
  11. XThis is the second posting of the generic assembler. Some notes:
  12. X
  13. X- I broke it down into some modules to assist recompilation.
  14. X
  15. X- As several have noted, this is not a modern assembler; its modelled
  16. Xafter the vintage assemblers of my youth, where the ops were ops, and
  17. Xoperands were operands, and operands didn't go around trying to be ops,
  18. Xand.... (sorry - too many movies lately). Anyway, that was to make it
  19. Xgeneric; its more difficult the other way.  Problem is that it makes doing
  20. Xthe 6805 and 6809 quite messy.  I experimented with extending the current
  21. Xregime to the 6809, and am disappointed by the results (to put it mildly -
  22. Xashamed would be closer). Anyway, I have to send this off with the problem
  23. Xunsolved as of now.  I'm open to ideas.
  24. X
  25. X- Several bug fixes from Mark Callaghan in Australia: VAX byte swapping (I
  26. Xdid the work on a Sun, and forgot about the other wretched machines);
  27. Xchecksumming the address & byte count (and negating it); a casting problem
  28. Xin putoutbin; and adding an error if no end statemnt is found (and
  29. Xsimulating it anyway). Thanks, Mark.
  30. X
  31. X- An error in the 6502 was fixed.
  32. X
  33. X- Made the instruction mask long.
  34. X
  35. X- Makeops is a filter that adds a sort of macro capability to the creating
  36. Xof the ops.h files. See 6809_ops.h (but ignore the content - its grotesque).
  37. X
  38. X- At this time I'm porting it to an AT. Will repost when that's complete.
  39. X
  40. X--------------------------------------------------------------------------
  41. X
  42. XSimplicity itself: edit the Makefile, equating V to the machine number of
  43. Xthe assembler to be made, and say make. You've got an assembler.
  44. X
  45. XMachines available: 6502, 8085, 6803, 6809.
  46. X
  47. X6803reg.h has some specific register names for special hardware registers
  48. Xon the 6803.
  49. X
  50. XI would appreciate getting back any new ops.h files anyone cares to
  51. Xgenerate (or maybe regenerate). Send them to hao!cisden!lmc, or to
  52. X
  53. X    Lyle McElhaney
  54. X    2489 W. Ridge Road
  55. X    Littleton, CO 80120
  56. X
  57. XPS: Equates in asm.h may need tweaking (like NORMBYTE, fer instance).
  58. @FUNKY STUFF~
  59. echo extracting - Makefile
  60. sed 's/^X//' > Makefile << '@FUNKY STUFF~'
  61. XOBJS=asm.o instructions.o pseudos.o data.o
  62. XV=6502
  63. XCFLAGS=-O
  64. X
  65. Xasm:    $(OBJS)
  66. X    cc $(OBJS) -o asm
  67. X
  68. X$(OBJS):  asm.h
  69. X
  70. Xdata.o: ops.h
  71. X
  72. Xops.h: $V_ops.h makeops
  73. X    makeops <$V_ops.h >ops.h
  74. X
  75. Xmakeops: makeops.o
  76. X    cc makeops.o -o makeops
  77. X
  78. Xclean:
  79. X    rm -f asm makeops ops.h *.o dist_asm*
  80. X
  81. Xdistrib: clean
  82. X    shar README Makefile *.c *.[1-9] > dist_asm1
  83. X    shar *.h > dist_asm2
  84. X    ls -l dist*
  85. @FUNKY STUFF~
  86. echo extracting - asm.c
  87. sed 's/^X//' > asm.c << '@FUNKY STUFF~'
  88. X#include "asm.h"
  89. X
  90. Xmain (argc, argv)
  91. X    int argc;
  92. X    char **argv;
  93. X{
  94. X    char *t1, *t2;
  95. X
  96. X    srcin = stdin;
  97. X    filename[0] = "stdin";
  98. X    binout = stdout;
  99. X    getargs (argc, argv);
  100. X    init ();
  101. X    output = fopen ((t1 = mktemp ("/tmp/asm185XXXXXX")), "w+");
  102. X    input[0] = srcin;
  103. X    if (process ()) reporterr (E_PASS1);
  104. X    (void) fclose (input[0]);
  105. X    init2 ();
  106. X    rewind (output);
  107. X    input[0] = output;
  108. X    output = fopen ((t2 = mktemp ("/tmp/asm285XXXXXX")), "w+");
  109. X    if (process ()) reporterr (E_PASS2);
  110. X    (void) fclose (input[0]);
  111. X    (void) unlink (t1);
  112. X    input[0] = output;
  113. X    output = binout;
  114. X    rewind (input[0]);
  115. X    sort ();
  116. X    (void) fclose (input[0]);
  117. X    (void) unlink (t2);
  118. X    (void) fclose (output);
  119. X    if (xref) crossref ();
  120. X    exit (errorstat);
  121. X}
  122. X
  123. X
  124. X/*      Current arguments:
  125. X        infile  input file name (default stdin)
  126. X        -lfile  listing output to file (default no listing),
  127. X            (default file is infile.l);
  128. X        -ofile  binary output to file (default binary to stdout),
  129. X            (default file is infile.o);
  130. X        -xfile  cross reference output to listing file (default no xref);
  131. X*/
  132. Xvoid getargs (argc, argv)
  133. X    int argc;
  134. X    char **argv;
  135. X{
  136. X    char *cp, *arg, *lname, *oname;
  137. X
  138. X    while (--argc) {
  139. X        arg = *(++argv);
  140. X        if (*arg == '-') {
  141. X            switch (*(++arg)) {
  142. X            case 'l':
  143. X                listing ++;
  144. X                lname = ++arg;
  145. X                break;
  146. X            case 'o':
  147. X                binary ++;
  148. X                oname = ++arg;
  149. X                break;
  150. X            case 'x':
  151. X                xref ++;
  152. X                break;
  153. X            }
  154. X        } else {
  155. X            name = arg;
  156. X            if ((srcin = fopen (name, "r")) == NULL)
  157. X                reporterr (E_INPUT);
  158. X            filename[0] = strcpy (malloc ((unsigned) strlen (name) + 1), name);
  159. X            if (cp = index (name, '.'))
  160. X                *cp = '\0';
  161. X        }
  162. X    }
  163. X    if (binary) {
  164. X        if (!*oname) {
  165. X            (void) strcat (strcpy (buf, name), ".o");
  166. X            oname = buf;
  167. X        }
  168. X        binout = fopen (oname, "w");
  169. X    }
  170. X    if (listing || xref) {
  171. X        if (!*lname) {
  172. X            (void) strcat (strcpy (buf, name), ".l");
  173. X            lname = buf;
  174. X        }
  175. X        list = fopen (lname, "w");
  176. X    }
  177. X    return;
  178. X}
  179. X
  180. X
  181. Xvoid init ()
  182. X{
  183. X    symbol *spt;
  184. X    int i;
  185. X
  186. X    lc = seghd->lc = 0;
  187. X    symtab = (symbol *) malloc ((unsigned) sizeof (symbol) * NSYMS);
  188. X    for (i = 0; i < NSYMS; i++)
  189. X        symtab->name = (char *) 0;
  190. X    for (spt = predef; *(spt->name); spt++)
  191. X        insert (spt->name, spt->value, spt->type, spt->segp, NO);
  192. X    end_found = 0;
  193. X    return;
  194. X}
  195. X
  196. X
  197. Xvoid init2 ()
  198. X{
  199. X    segmnt *sp;
  200. X    Memad acc;
  201. X
  202. X    acc = seghd->lc;
  203. X    seghd->lc = 0;
  204. X    for (sp = seghd->next; sp; sp = sp->next) {
  205. X        acc += sp->lc;
  206. X        sp->lc = sp->start = acc - sp->lc;
  207. X    }
  208. X    curseg = seghd;
  209. X    lc = curseg->lc;
  210. X    errorstat =
  211. X    end_found =
  212. X        0;
  213. X    return;
  214. X}
  215. X
  216. X
  217. X
  218. X/*      Gross syntax rules:      <and the rest of us simply obey>
  219. X    Input line:     [label] [op[optop] [operands]]
  220. X    Comments: Blank lines and anything following ';'
  221. X    White space is any combination of blank and/or tab chars.
  222. X    Operands & optop cannot contain white space (except within strings)
  223. X        and are separated by commas. There must be the exact number of
  224. X        operands that the instruction expects.
  225. X    optop can be anything, and is interpreted by the machine-specific
  226. X        routine "optional". It is distinguished from op by starting
  227. X        with a non-alphanumeric or upper-case character.
  228. X    Label must start in col 1 if it exists.
  229. X*/
  230. Xint process ()
  231. X{
  232. X    char *ipt;
  233. X    int i, done;
  234. X    static char *zit = "";
  235. X
  236. X    pass ++;
  237. X    lineno[0] = 0;
  238. Xcontproc:
  239. X    while (fgets (buf, LINEBUFLEN, input[currinput]) != NULL) {
  240. X        (void) strcpy (linecopy, buf);
  241. X        linecopy[strlen(linecopy)-1] = 0;
  242. X        if (pass == 1) fputs (buf, output);
  243. X        lineno[currinput]++;
  244. X        ipt = buf;
  245. X        label = ipt;
  246. X        op = opd = optop = zit;
  247. X        while (islabel (*ipt)) ipt++;
  248. X        if (iseol (*ipt))
  249. X            goto shortline;
  250. X        *ipt++ = 0;
  251. X        while (iswhite (*ipt)) ipt++;
  252. X        if (iseol (*ipt)) {
  253. Xshortline:              if (pass == 2)
  254. X                listit (linecopy, lc, dummy, 0);
  255. X            continue;
  256. X        }
  257. X        op = ipt;
  258. X        while (isalnum (*ipt)) ipt++;
  259. X        if (iseol (*ipt)) {
  260. X            *ipt = 0;
  261. X            goto parsed;
  262. X        }
  263. X        if (!iswhite(*ipt) && islower(*ipt))
  264. X            (void) strcpy ((optop = malloc (strlen (ipt) + 1)), ipt);
  265. X        *ipt++ = 0;
  266. X        while (iswhite (*ipt)) ipt++;
  267. X        opd = ipt;
  268. X        while (*ipt != '\n') ipt++;
  269. X        *ipt = 0;
  270. Xparsed:
  271. X        if ((i = opsrch (op, pseudotab, pseudolen)) >= 0) {
  272. X            done = (pseudotab[i].action) ();
  273. X        } else if ((i = opsrch (op, optab, instrlen)) >= 0) {
  274. X            (void) (optab[i].action) (i);
  275. X        } else {
  276. X            reporterr (E_ILLOP);
  277. X            listit (linecopy, lc, dummy, 0);
  278. X        }
  279. X        if (done) break;
  280. X    }
  281. X    if (!end_found) {
  282. X        do_end();
  283. X        reporterr (E_NOEND);
  284. X    }
  285. X    if (currinput > 0) {
  286. X        free (filename[currinput]);
  287. X        filename[currinput] = NULL;
  288. X        (void) fclose (input[currinput--]);
  289. X        goto contproc;
  290. X    }
  291. X    return (errorstat);
  292. X}
  293. X
  294. Xint opsrch (op, table, hi)
  295. X    char *op;
  296. X    opdef table[];
  297. X    int hi;
  298. X{
  299. X    int lo, mid, i;
  300. X
  301. X/*      Binary search - assumes that list extends from optab[0] through
  302. X    optab[hi-2] inclusive. The hi and lo indicies always point to
  303. X    ruled out table locations plus 1, to keep away from rounding
  304. X    problems on the far side of zero. Whenever they come to within 1
  305. X    of each other, the jig is up (and gone......)
  306. X*/
  307. X
  308. X    lo = 0;
  309. X    while (1) {
  310. X        mid = (hi + lo) / 2;
  311. X        if ((i = strcmp (table[mid - 1].name, op)) == 0)
  312. X            return (--mid);
  313. X        else if (i > 0)
  314. X            hi = mid;
  315. X        else
  316. X            lo = mid;
  317. X        if (hi - lo <= 1) break;
  318. X    }
  319. X    return (-1);
  320. X}
  321. X
  322. X
  323. Xvoid listit (line, xlc, binbuf, length)
  324. X    char *line;
  325. X    Memad xlc;
  326. X    Word binbuf[];
  327. X    int length;
  328. X{
  329. X    int addit, i;
  330. X
  331. X    addit = 0;
  332. X    do {
  333. X        listint (line, xlc + addit, &binbuf[addit], length - addit);
  334. X        addit += listlen;
  335. X        line = (char *)0;
  336. X    } while (addit < length);
  337. X    return;
  338. X}
  339. X
  340. X
  341. Xvoid listint (line, xlc, binbuf, length)
  342. X    char *line;
  343. X    Memad xlc;
  344. X    Word *binbuf;
  345. X    int length;
  346. X{
  347. X    int i;
  348. X
  349. X    if (listing && liston) {
  350. X        (void) fprintf (list, "%4ld %08x: ", lineno[currinput], xlc);
  351. X        if (length > listlen) length = listlen;
  352. X        for (i = 0; i < length; i++)
  353. X            (void) fprintf (list, "%02x ", binbuf[i]);
  354. X        for (; i < listlen; i++)
  355. X            (void) fprintf (list, "   ");
  356. X        /* move up to an 8 byte (tab) boundary */
  357. X        for (i = 0; i < (81-3*listlen)%8; i++)
  358. X            (void) fprintf (list, " ");
  359. X        if (line) (void) fprintf (list, "%s", line);
  360. X        (void) fprintf (list, "\n");
  361. X    }
  362. X    return;
  363. X}
  364. X
  365. X
  366. X/*      Binary output format:
  367. X
  368. X    Intel standard hexadecimal format!!!!
  369. X
  370. X        Output is a series of variable length records consisting of ascii
  371. X        characters 0-9, A-F (0x30-0x39, 0x41-0x6). Each character contains
  372. X        four bits of significant data; two such characters form a binary
  373. X    byte of data, the binary equivalent to the hexadecimal ascii
  374. X    characters.
  375. X
  376. X    The data records have the format:
  377. X
  378. X                        /  len covers this \
  379. X    +---+---+---+---+---+---+---+---+---+--------//--------+---+---+
  380. X    | : |  len  |    address    | 0 | 0 |    data bytes    | cksum |
  381. X    +---+---+---+---+---+---+---+---+---+--------//--------+---+---+
  382. X        \             checksum covers this                 /
  383. X
  384. X    Checksum computed such that sum of all bytes except ':' modulo
  385. X    the bytelength is 0.
  386. X
  387. X    End Record:
  388. X
  389. X    +---+---+---+---+---+---+---+---+---+---+---+
  390. X    | : | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | f | f |
  391. X    +---+---+---+---+---+---+---+---+---+---+---+
  392. X
  393. X
  394. X*/
  395. Xvoid putoutbin (binbuf, length)
  396. X    Word binbuf[];
  397. X    int length;
  398. X{
  399. X    static Memad address;
  400. X    static int count;
  401. X    static Word checksum;
  402. X    static Word array[BINBUFLEN];
  403. X    static Word *curpt = 0;
  404. X    static Memad binlc = ~0;
  405. X    int i;
  406. X
  407. X    if (binlc != lc) {
  408. X        if (curpt != 0) {
  409. X            (void) fwrite (":", 1, 1, output);
  410. X            putout ((Word) count);
  411. X            putout ((Word) (address >> 8));
  412. X            putout ((Word) (address & 0xff));
  413. X            (void) fwrite ("00", 2, 1, output);
  414. X            for (i = 0; i < count; i++)
  415. X                putout (array[i]);
  416. X            checksum += (count & 0xff) +
  417. X                    (address >> 8) +
  418. X                    (address & 0xff);
  419. X            putout (-checksum);
  420. X            if (length == 0) {
  421. X                (void) fwrite (":00000001ff", 11, 1, output);
  422. X            }
  423. X        }
  424. X        curpt = array;
  425. X        count = 0;
  426. X        address = binlc = lc;
  427. X        checksum = 0;
  428. X    }
  429. X    for (i = 0; i < length; i++) {
  430. X        *curpt++ = binbuf[i];
  431. X        checksum += binbuf[i];
  432. X        count++;
  433. X        binlc ++;
  434. X    }
  435. X    if (count > BINBUFLEN - MAXBYTPERINS)
  436. X        binlc = 0;
  437. X    return;
  438. X}
  439. X
  440. X#define hex(x) x+(x<10?'0':'7')
  441. X
  442. Xvoid putout (c)
  443. X    Word c;
  444. X{
  445. X    Word outc[2], t;
  446. X
  447. X    t = c>>4;
  448. X    c &= 0xf;
  449. X    outc[0] = hex(t);
  450. X    outc[1] = hex(c);
  451. X    (void) fwrite ((char *)outc, 2, 1, output);
  452. X    return;
  453. X}
  454. X
  455. X
  456. Xvoid insert (name, value, type, segment, mult)
  457. X    char *name;
  458. X    long value;
  459. X    opdclass *type;
  460. X    segmnt *segment;
  461. X    int mult;
  462. X{
  463. X    int x, y;
  464. X    symbol *sp;
  465. X
  466. X    x = y = hash (name);
  467. X    while ((sp = &symtab[x])->name != (char *) 0) {
  468. X        if (strcmp (sp->name, name) == 0) {
  469. X            if (!mult && value != sp->value && pass == 1) {
  470. X                reporterr (E_MULT);
  471. X                return;
  472. X            }
  473. X            break;
  474. X        }
  475. X        if (++x == y) reporterr (E_STOFLO);
  476. X        if (x == NSYMS) x = 0;
  477. X    }
  478. X    sp->name = malloc ((unsigned) strlen (name) + 1);
  479. X    (void) strcpy (sp->name, name);
  480. X    sp->value = value;
  481. X    sp->type = type;
  482. X    sp->segp = segment;
  483. X    return;
  484. X}
  485. X
  486. X
  487. Xint lookup (name)
  488. X    char *name;
  489. X{
  490. X    int x, y;
  491. X
  492. X    x = y = hash (name);
  493. X    while (symtab[x].name != (char *) 0) {
  494. X        if (strcmp (name, symtab[x].name) == 0)
  495. X            return (x);
  496. X        x++;
  497. X        if (x == y) return (-1);
  498. X        if (x == NSYMS) x = 0;
  499. X    }
  500. X    return (-1);
  501. X}
  502. X
  503. X
  504. Xint hash (string)
  505. X    char *string;
  506. X{
  507. X    char *pt;
  508. X    int tot;
  509. X
  510. X    tot = 0;
  511. X    for (pt = string; *pt; pt++)
  512. X        tot += *pt;
  513. X    if (NSYMS >= 256)
  514. X        tot += (tot << 8);
  515. X    return (tot % NSYMS);
  516. X}
  517. X
  518. X
  519. Xvoid reporterr (errcode)
  520. X    int errcode;
  521. X{
  522. X    static char *elist[] = {
  523. X        "",
  524. X        "aborting at end of pass1",
  525. X        "aborting at end of pass2",
  526. X        "symbol table overflow",
  527. X        "input file error",
  528. X        "too many nested includes",
  529. X        "include syntax error",
  530. X        "illegal expression",
  531. X        "undefined symbol",
  532. X        "unknown op code",
  533. X        "multiply defined symbol",
  534. X        "insufficient operands",
  535. X        "value too large for field",
  536. X        "unsigned value negative",
  537. X        "segment violation",
  538. X        "opcode suffix syntax",
  539. X        "no end statement - simulated",
  540. X    };
  541. X
  542. X    if (pass == 1) {
  543. X        if (list)
  544. X            (void) fprintf (list, "----> Error in file %s, line %d: %s\n", filename[currinput], lineno[currinput], elist[errcode]);
  545. X        (void) fprintf (stderr, "----> Error in file %s, line %d: %s\n", filename[currinput], lineno[currinput], elist[errcode]);
  546. X    } else {
  547. X        if (list)
  548. X            (void) fprintf (list, "----> %s: %s\n", filename[currinput], elist[errcode]);
  549. X        (void) fprintf (stderr, "----> %s: %s\n", filename[currinput], elist[errcode]);
  550. X    }
  551. X    (void) fflush (list);
  552. X    if (errcode <= A_MAX) {
  553. X        (void) fprintf (stderr, "asm: Abort error: %s\n", elist[errcode]);
  554. X        exit (1);
  555. X    }
  556. X    errorstat++;
  557. X    return;
  558. X}
  559. X
  560. X
  561. Xvoid sort ()
  562. X{
  563. X    char c;
  564. X
  565. X    while ((c = getc (input[0])) > 0)
  566. X        putc (c, output);
  567. X    return;
  568. X}
  569. X
  570. X
  571. Xvoid crossref ()
  572. X{
  573. X    int i, j, k, gap;
  574. X    symbol symtemp;
  575. X
  576. X    (void) fprintf (list, "\n\n\n                     Cross Reference\n\n");
  577. X    k = 0;
  578. X    for (i = 0; i < NSYMS; i++)
  579. X        if (symtab[i].name && *symtab[i].name)
  580. X            symtab[k++] = symtab[i];
  581. X    for (gap = k / 2; gap > 0; gap /= 2)
  582. X        for (i = gap; i < k; i++)
  583. X            for (j = i - gap; j >= 0; j -= gap) {
  584. X                if (strcmp (symtab[j].name,
  585. X                          symtab[j+gap].name) <= 0)
  586. X                    break;
  587. X                symtemp = symtab[j];
  588. X                symtab[j] = symtab[j+gap];
  589. X                symtab[j+gap] = symtemp;
  590. X            }
  591. X    for (i = 0; i < k; i++)
  592. X        (void) fprintf (list, "    %s: 0x%x\n", symtab[i].name,
  593. X                            symtab[i].value);
  594. X    return;
  595. X}
  596. @FUNKY STUFF~
  597. echo extracting - data.c
  598. sed 's/^X//' > data.c << '@FUNKY STUFF~'
  599. X#include "asm.h"
  600. X
  601. Xopdclass o_none  = {0, 0, 0, 0};
  602. Xinsclass i_noopd = {1, 0, &o_none, &o_none, 0, 0};
  603. Xopdef pseudotab[] = {
  604. X    "bss"    , &i_noopd, 0x00, do_bss   ,
  605. X    "data"   , &i_noopd, 0x00, do_data  ,
  606. X    "data2"  , &i_noopd, 0x00, do_data2 ,
  607. X    "end"    , &i_noopd, 0x00, do_end   ,
  608. X    "equ"    , &i_noopd, 0x00, do_equ   ,
  609. X    "include", &i_noopd, 0x00, do_incl  ,
  610. X    "listoff", &i_noopd, 0x00, do_loff  ,
  611. X    "liston" , &i_noopd, 0x00, do_lon   ,
  612. X    "org"    , &i_noopd, 0x00, do_org   ,
  613. X    "seg"    , &i_noopd, 0x00, do_seg   ,
  614. X    "set"    , &i_noopd, 0x00, do_set   ,
  615. X    "string" , &i_noopd, 0x00, do_string,
  616. X    ""       , &i_noopd, 0x00, 0
  617. X};
  618. X
  619. XFILE *input[INCLSTACK], *output, *list = (FILE *)0, *srcin, *binout;
  620. Xchar *name, *label, *op, *opd, *optop;
  621. Xchar buf[LINEBUFLEN], linecopy[LINEBUFLEN], *filename[INCLSTACK];
  622. Xint lineno[INCLSTACK], ignerr, end_found;
  623. Xint errorstat=0, currinput=0, pass=0, liston=YES, listing=0, binary=0, xref=0;
  624. Xsymbol *symtab; Memad lc; Word *dummy;
  625. Xsegmnt segmain={0, 0, "", 0};
  626. Xsegmnt *seghd = &segmain, *curseg = &segmain, *exprseg;
  627. X
  628. X#include "ops.h"
  629. X
  630. Xint listlen = BYTESPERLINE;
  631. Xint pseudolen = sizeof (pseudotab) / sizeof (opdef);
  632. Xint instrlen = sizeof (optab) / sizeof (opdef);
  633. @FUNKY STUFF~
  634. echo extracting - instructions.c
  635. sed 's/^X//' > instructions.c << '@FUNKY STUFF~'
  636. X#include "asm.h"
  637. X
  638. Xint choiceinstr (ins)
  639. X    int ins;
  640. X{
  641. X    choicedef *chpt;
  642. X    int num, i, fits;
  643. X    Long value;
  644. X    static char *opdpt;
  645. X
  646. X    if (label && *label)
  647. X        insert (label, (long) lc, &o_none, curseg, NO);
  648. X    chpt = (choicedef *)optab[ins].class;
  649. X    num = chpt->field;
  650. X    for (opdpt = opd; num > 1; num --) {
  651. X        opdpt = index (opdpt, ',');
  652. X        if (opdpt == NULL) {
  653. X            reporterr (E_NOPS);
  654. X            return (0);
  655. X        }
  656. X        opdpt++;
  657. X    }
  658. X    value = expr (&opdpt, &i, YES);
  659. X    fits = i ? NO :
  660. X        (value >= chpt->lorange &&
  661. X         value <= chpt->hirange &&
  662. X         curseg == exprseg);
  663. X    if ((i = opsrch ((fits ? chpt->rname : chpt->nname),
  664. X                         optab, instrlen)) >= 0) {
  665. X        (optab[i].action) (i);
  666. X    } else {
  667. X        reporterr (E_ILLOP);
  668. X    }
  669. X    return (0);
  670. X}
  671. X
  672. X
  673. Xint geninstr (ins)
  674. X    int ins;
  675. X{
  676. X    static Acc cons = ~0L;
  677. X    int nargs, length, i, j, k;
  678. X    opdclass *oclass;
  679. X    insclass *iclass;
  680. X    Word itemtemp, obuf[MAXBYTPERINS];
  681. X    Acc mask;
  682. X    char *nextopd;
  683. X    itemu item;
  684. X
  685. X    if (label && *label)
  686. X        insert (label, (long) lc, &o_none, curseg, NO);
  687. X    iclass = optab[ins].class;
  688. X    length = iclass->length;
  689. X    if (pass == 2) {
  690. X        nargs = iclass->mopds;
  691. X        for (i = 0; i < MAXBYTPERINS; i++)
  692. X            obuf[i] = 0;
  693. X        item.l = optab[ins].mask;
  694. X        for (i = 0; i < MINBYTES; i++)
  695. X            obuf[i] = item.s[i];
  696. X        item.l = 0L;
  697. X        nextopd = opd;
  698. X        for (j = 0; j < nargs; j++) {
  699. X            if (j != 0) {
  700. X                if (*nextopd != ',') {
  701. X                    reporterr (E_NOPS);
  702. X                } else {
  703. X                    nextopd++;
  704. X                }
  705. X            }
  706. X            oclass = iclass->type[j];
  707. X            item.l = expr (&nextopd, &ignerr, NO) + oclass->offset -
  708. X                (oclass->relative ? lc : 0);
  709. X            mask = cons >> (LONGLEN - oclass->length);
  710. X            if (item.l < 0L && !oclass->signed)
  711. X                reporterr (E_NEG);
  712. X            if (((item.ls < 0L && oclass->signed) ? -item.ls : item.ls) & ~mask)
  713. X                reporterr (E_TOOBIG);
  714. X            item.l &= mask;
  715. X            if (oclass->byteswapped) {
  716. X                itemtemp = item.s[BYTPERLONG - 2];
  717. X                item.s[BYTPERLONG - 2] = item.s[BYTPERLONG - 1];
  718. X                item.s[BYTPERLONG - 1] = itemtemp;
  719. X            }
  720. X            i = LONGLEN - 8 - iclass->offset[j];
  721. X            item.l <<= (i % 8);
  722. X            i /= 8;
  723. X            k = 0;
  724. X            if (i < 0)
  725. X                k = -i, i = 0;
  726. X            for (; k < MAXBYTPERINS && i < BYTPERLONG; k++, i++)
  727. X#ifdef NORMBYTE
  728. X                obuf[k] |= item.s[i];
  729. X#else
  730. X                obuf[k] |= item.s[BYTPERLONG-1-i];
  731. X#endif
  732. X        }
  733. X        if (optop) {
  734. X            optional (optop, obuf);
  735. X            free (optop);
  736. X        }
  737. X        putoutbin (obuf, length);
  738. X        listit (linecopy, lc, obuf, length);
  739. X    }
  740. X    lc += length;
  741. X    return (0);
  742. X}
  743. X
  744. Xlong expr (string, errind, test)
  745. X    char **string;
  746. X    int *errind;
  747. X    int test;
  748. X{
  749. X    long exp, val;
  750. X    int op, err;
  751. X    int uniop = 0;
  752. X    segmnt *seg1, *seg2;
  753. X
  754. X    *errind = NO;
  755. X    if (**string == '-')
  756. X        uniop = 1;
  757. X    else if (**string == '~')
  758. X        uniop = 2;
  759. X    if (uniop)
  760. X        (*string)++;
  761. X    exp = getval(string, &err, test, &seg1);
  762. X    if (err) goto errorexit;
  763. X    if (uniop == 2)
  764. X        exp = ~exp;
  765. X    else if (uniop == 1)
  766. X        exp = -exp;
  767. X    while (!isdelim(**string)) {
  768. X        if ((op = getop (string)) == NOOP) {
  769. X            if (!test) reporterr (E_EXPR);
  770. Xerrorexit:              for (; !isdelim (**string); *string++)  ;
  771. X            *errind = YES;
  772. X            return (0);
  773. X        }
  774. X        val = getval (string, &err, test, &seg2);
  775. X        if (err) goto errorexit;
  776. X        if (seg1 && seg2 && seg1 != seg2 && pass == 1)
  777. X            reporterr (E_SEG);
  778. X        switch (op) {
  779. X        case PLUS:
  780. X            exp += val;
  781. X            break;
  782. X        case MINUS:
  783. X            exp -= val;
  784. X            break;
  785. X        case MULT:
  786. X            exp *= val;
  787. X            break;
  788. X        case DIV:
  789. X            exp /= val;
  790. X            break;
  791. X        case MOD:
  792. X            exp %= val;
  793. X            break;
  794. X        case OR:
  795. X            exp |= val;
  796. X            break;
  797. X        case AND:
  798. X            exp &= val;
  799. X            break;
  800. X        case EXOR:
  801. X            exp ^= val;
  802. X            break;
  803. X        case SHLF:
  804. X            exp <<= val;
  805. X            break;
  806. X        case SHRT:
  807. X            exp >>= val;
  808. X            break;
  809. X        default:
  810. X            if (!test) reporterr (E_EXPR);
  811. X        }
  812. X        seg1 = seg2;
  813. X    }
  814. X    exprseg = seg1;
  815. X    return (exp);
  816. X}
  817. X
  818. X
  819. X/*      Snag literals and variable names. The literal classes are:
  820. X
  821. X    [digit]....[digit]      unsigned decimal number
  822. X    0[hexdigit]...[hexdigit]unsigned hexadecimal number
  823. X    $                       current location counter
  824. X    '[char]                 single character, right just, zero fill
  825. X    "[char][char]           character pair
  826. X
  827. X    Returns a 16 bit value. Unary operations taken care of in expr;
  828. X    byte swapping done if required by geninstr.
  829. X*/
  830. Xlong getval (strpt, errorret, test, segment)
  831. X    segmnt **segment;
  832. X    char **strpt;
  833. X    int *errorret;
  834. X    int test;
  835. X{
  836. X    long total;
  837. X    char name[33], *npt;
  838. X    int i;
  839. X
  840. X    *segment = (segmnt *) 0;
  841. X    *errorret = 0;
  842. X    total = 0L;
  843. X    if (isdigit (**strpt)) {
  844. X        if (**strpt == '0') {
  845. X            while (isxdigit (**strpt)) {
  846. X                total *= 16;
  847. X                total += xtod (**strpt);
  848. X                (*strpt)++;
  849. X            }
  850. X        } else {
  851. X            while (isdigit (**strpt)) {
  852. X                total *= 10;
  853. X                total += (Long)(**strpt - '0');
  854. X                (*strpt)++;
  855. X            }
  856. X        }
  857. X    } else if (islabel (**strpt)) {
  858. X        npt = name;
  859. X        while (islabel (**strpt)) {
  860. X            *npt++ = **strpt;
  861. X            (*strpt)++;
  862. X        }
  863. X        *npt = '\0';
  864. X        if ((i = lookup (name)) == -1) {
  865. X            if (pass == 2)
  866. X                if (!test) reporterr (E_UNDEF);
  867. X            *errorret = 1;
  868. X            total = 0L;
  869. X        } else {
  870. X            total = symtab[i].value;
  871. X            if (pass == 2 && symtab[i].segp)
  872. X                total += (symtab[i].segp)->start;
  873. X            *segment = symtab[i].segp;
  874. X        }
  875. X    } else if (**strpt == '\'') {
  876. X        (*strpt)++;
  877. X        if (**strpt == '\\') {
  878. X            (*strpt)++;
  879. X            total = escape (strpt);
  880. X        } else {
  881. X            total = **strpt;
  882. X            (*strpt)++;
  883. X        }
  884. X    } else if (**strpt == '"') {
  885. X        (*strpt)++;
  886. X        if (**strpt == '\\') {
  887. X            (*strpt)++;
  888. X            total = escape (strpt);
  889. X        } else {
  890. X            total = **strpt;
  891. X            (*strpt)++;
  892. X        }
  893. X        total <<= 8;
  894. X        if (**strpt == '\\') {
  895. X            (*strpt)++;
  896. X            total |= escape (strpt);
  897. X        } else {
  898. X            total |= **strpt;
  899. X            (*strpt)++;
  900. X        }
  901. X    } else if (**strpt == '$') {
  902. X        total = lc;
  903. X        *segment = curseg;
  904. X        (*strpt)++;
  905. X    } else {
  906. X        if (!test) reporterr (E_EXPR);
  907. X        *errorret = 1;
  908. X    }
  909. X    return (total);
  910. X}
  911. X
  912. X
  913. Xchar escape (st)
  914. X    char **st;
  915. X{
  916. X    switch (*((*st)++)) {
  917. X    case 'b':
  918. X        return ('\b');
  919. X    case 'n':
  920. X        return ('\n');
  921. X    case 'r':
  922. X        return ('\r');
  923. X    case '^':
  924. X        return ('\033');
  925. X    case 'f':
  926. X        return ('\f');
  927. X    case 't':
  928. X        return ('\t');
  929. X    case '?':
  930. X        return ('\177');
  931. X    case '\\':
  932. X        return ('\\');
  933. X    default:
  934. X        (*st)--;
  935. X        if (isxdigit (**st) && isxdigit (*(*st + 1))) {
  936. X            *st += 2;
  937. X            return (xtod (*(*st - 2)) << 4 | xtod (*(*st - 1)));
  938. X        } else {
  939. X            return (*(*st++));
  940. X        }
  941. X    }
  942. X}
  943. X
  944. X
  945. Xint xtod (c)
  946. X    char c;
  947. X{
  948. X    return ((int) c - (c > '9' ? (c > 'F' ? 'W' : '7') : '0'));
  949. X}
  950. X
  951. X
  952. Xint getop (string)
  953. X    char **string;
  954. X{
  955. X    static char ops[] = OPSTRING;
  956. X    char *k;
  957. X
  958. X    for (k = ops; *k; k++)
  959. X        if (*k == **string) {
  960. X            (*string)++;
  961. X            return ((int) (k - ops));
  962. X        }
  963. X    (*string)++;
  964. X    return (NOOP);
  965. X}
  966. @FUNKY STUFF~
  967. echo extracting - makeops.c
  968. sed 's/^X//' > makeops.c << '@FUNKY STUFF~'
  969. X#include <stdio.h>
  970. X#include <ctype.h>
  971. X
  972. X#define iswhite(x) (x)==' '||(x)=='\t'||(x)==','
  973. X#define skipword  while(isalnum(*pt)||*pt=='_')pt++;
  974. X#define skipwhite while(iswhite(*pt))pt++;
  975. X
  976. Xstruct {
  977. X    char *name, *str;
  978. X} entry[100];
  979. X
  980. Xint ep, entryn = 0;
  981. Xchar buf[140], hold[2048];
  982. Xchar *pt, *pt2, *name, *arg1, *arg2;
  983. X
  984. Xextern int strncmp(), strcmp();
  985. X
  986. Xmain ()
  987. X{
  988. X    while (gets (buf) > 0) {
  989. X    if (strncmp (buf, "beginpattern", 12) == 0) {
  990. X        pt = buf;
  991. X        skipword;
  992. X        skipwhite;
  993. X        entry[entryn].name = (char *) malloc (strlen (pt) + 1);
  994. X        strcpy (entry[entryn].name, pt);
  995. X        pt = hold;
  996. X        while (gets (buf) > 0 && strncmp (buf, "endpattern", 10) != 0) {
  997. X        strcpy (pt, buf);
  998. X        pt += strlen (pt);
  999. X        *pt++ = '\n';
  1000. X        }
  1001. X        *pt = '\0';
  1002. X        entry[entryn].str = (char *) malloc (strlen (hold) + 1);
  1003. X        strcpy (entry[entryn].str, hold);
  1004. X        entryn++;
  1005. X    } else if (strncmp (buf, "pattern", 7) == 0) {
  1006. X        pt = buf;
  1007. X        skipword;
  1008. X        skipwhite; name = pt; skipword; *pt++ = 0;
  1009. X        skipwhite; arg1 = pt; skipword; *pt++ = 0;
  1010. X        skipwhite; arg2 = pt; skipword; *pt = 0;
  1011. X        for (ep = 0; ep < entryn; ep++) {
  1012. X        if (strcmp (name, entry[ep].name) == 0) {
  1013. X            for (pt = entry[ep].str; *pt; pt++) {
  1014. X            if (*pt == '~') {
  1015. X                switch (*(++pt)) {
  1016. X                case '1':
  1017. X                pt2 = arg1;
  1018. X                goto argout;
  1019. X                case '2':
  1020. X                pt2 = arg2;
  1021. X       argout:                  while (*pt2) {
  1022. X                    putchar (*pt2++);
  1023. X                }
  1024. X                break;
  1025. X                default:
  1026. X                putchar ('~');
  1027. X                putchar (*pt);
  1028. X                }
  1029. X            } else {
  1030. X                putchar (*pt);
  1031. X            }
  1032. X            }
  1033. X            goto nextch;
  1034. X        }
  1035. X        }
  1036. X        fprintf (stderr, "makeops: can't find macro %s\n", name);
  1037. Xnextch:     ;
  1038. X    } else {
  1039. X        puts (buf);
  1040. X    }
  1041. X    }
  1042. X    exit (0);
  1043. X}
  1044. @FUNKY STUFF~
  1045. echo extracting - pseudos.c
  1046. sed 's/^X//' > pseudos.c << '@FUNKY STUFF~'
  1047. X#include "asm.h"
  1048. X
  1049. Xint do_incl ()
  1050. X{
  1051. X    if (pass == 1) {
  1052. X        char *ip;
  1053. X
  1054. X        if (++currinput > INCLSTACK)
  1055. X            reporterr (E_INCL);
  1056. X        opd++;
  1057. X        if ((ip = index (opd, '"')) == 0)
  1058. X            reporterr (E_INCLSYN);
  1059. X        *ip = 0;
  1060. X        if ((input[currinput] = fopen (opd, "r")) == NULL)
  1061. X            reporterr (E_INPUT);
  1062. X        filename[currinput] = strcpy (malloc ((unsigned) strlen (opd) + 1), opd);
  1063. X        lineno[currinput] = 0;
  1064. X    }
  1065. X    return (0);
  1066. X}
  1067. X
  1068. X
  1069. Xint do_org ()
  1070. X{
  1071. X    if (label && *label)
  1072. X        insert (label, (long) lc, &o_none, curseg, NO);
  1073. X    if (pass == 2)
  1074. X        listit (linecopy, lc, dummy, 0);
  1075. X    lc = (Memad) expr (&opd, &ignerr, NO);
  1076. X    return (0);
  1077. X}
  1078. X
  1079. X
  1080. Xint do_loff ()
  1081. X{
  1082. X    liston = NO;
  1083. X    return (0);
  1084. X}
  1085. X
  1086. X
  1087. Xint do_lon ()
  1088. X{
  1089. X    liston = YES;
  1090. X    return (0);
  1091. X}
  1092. X
  1093. X
  1094. Xint do_equ ()
  1095. X{
  1096. X    long eqtemp;
  1097. X
  1098. X    eqtemp = expr (&opd, &ignerr, NO);
  1099. X    if (label && *label)
  1100. X        insert (label, eqtemp, &o_none, exprseg, NO);
  1101. X    if (pass == 2)
  1102. X        listit (linecopy, eqtemp, dummy, 0);
  1103. X    return (0);
  1104. X}
  1105. X
  1106. X
  1107. Xint do_seg ()
  1108. X{
  1109. X    segmnt *sp, *osp;
  1110. X
  1111. X    curseg->lc = lc;
  1112. X    if (opd && *opd) {
  1113. X        for (sp = seghd; sp; osp = sp, sp = sp->next) {
  1114. X            if (strcmp (sp->name, opd) == 0) {
  1115. X                lc = sp->lc;
  1116. X                curseg = sp;
  1117. X                goto fin_seg;
  1118. X            }
  1119. X        }
  1120. X    } else {
  1121. X        lc = seghd->lc;
  1122. X        curseg = seghd;
  1123. X    }
  1124. X    curseg = osp->next = (segmnt *) malloc ((unsigned) sizeof (segmnt));
  1125. X    curseg->name = strcpy (malloc ((unsigned) strlen (opd) + 1), opd);
  1126. X    curseg->lc = lc = 0;
  1127. X    curseg->next = (segmnt *) 0;
  1128. Xfin_seg:
  1129. X    if (pass == 2)
  1130. X        listit (linecopy, lc, dummy, 0);
  1131. X    return (0);
  1132. X}
  1133. X
  1134. X
  1135. Xint do_set ()
  1136. X{
  1137. X    long eqtemp;
  1138. X
  1139. X    eqtemp = expr (&opd, &ignerr, NO);
  1140. X    if (label && *label)
  1141. X        insert (label, eqtemp, &o_none, exprseg, YES);
  1142. X    if (pass == 2)
  1143. X        listit (linecopy, eqtemp, dummy, 0);
  1144. X    return (0);
  1145. X}
  1146. X
  1147. X
  1148. Xint do_bss ()
  1149. X{
  1150. X    if (label && *label)
  1151. X        insert (label, (long) lc, &o_none, curseg, NO);
  1152. X    if (pass == 2)
  1153. X        listit (linecopy, lc, dummy, 0);
  1154. X    lc += (Memad) expr (&opd, &ignerr, NO);
  1155. X    return (0);
  1156. X}
  1157. X
  1158. X
  1159. Xint do_end ()
  1160. X{
  1161. X    end_found ++;
  1162. X    curseg->lc = lc;
  1163. X    if (pass == 2) {
  1164. X        listit (linecopy, lc, dummy, 0);
  1165. X        lc = 0xffff;
  1166. X        putoutbin (dummy, 0);
  1167. X    }
  1168. X    curseg = seghd;
  1169. X    return (1);
  1170. X}
  1171. X
  1172. X
  1173. Xint do_data ()
  1174. X{
  1175. X    Word temp, templist[MAXBYTPERINS];
  1176. X    char *tp;
  1177. X    int count;
  1178. X
  1179. X    if (label && *label)
  1180. X        insert (label, (long) lc, &o_none, curseg, NO);
  1181. X    tp = opd;
  1182. X    count = 1;
  1183. X    if (*opd == ':') {
  1184. X        ++opd;
  1185. X        count = expr (&opd, &ignerr, NO);
  1186. X        if (*opd == ':') {
  1187. X            opd ++;
  1188. X        } else {
  1189. X            reporterr (E_EXPR);
  1190. X            count = 1;
  1191. X            opd = tp;
  1192. X        }
  1193. X    }
  1194. X    if (pass == 2) {
  1195. X        int i, j;
  1196. X
  1197. X        temp = (Word) expr (&opd, &ignerr, NO);
  1198. X        for (i = 0; i < MAXBYTPERINS; i++)
  1199. X               templist[i] = temp;
  1200. X        listit (linecopy, lc, templist, count);
  1201. X        for (i = 0; i < count; i++)
  1202. X            putoutbin (&temp, 1);
  1203. X    }
  1204. X    lc += count;
  1205. X    return (0);
  1206. X}
  1207. X
  1208. X
  1209. Xint do_data2 ()
  1210. X{
  1211. X    Long temp;
  1212. X    char *tp;
  1213. X    int count;
  1214. X
  1215. X    if (label && *label)
  1216. X        insert (label, (long) lc, &o_none, curseg, NO);
  1217. X    tp = opd;
  1218. X    count = 1;
  1219. X    if (*opd == ':') {
  1220. X        ++opd;
  1221. X        count = expr (&opd, &ignerr, NO);
  1222. X        if (*opd == ':') {
  1223. X            opd ++;
  1224. X        } else {
  1225. X            reporterr (E_EXPR);
  1226. X            count = 1;
  1227. X            opd = tp;
  1228. X        }
  1229. X    }
  1230. X    if (pass == 2) {
  1231. X        int i;
  1232. X
  1233. X        temp = (Long) expr (&opd, &ignerr, NO);
  1234. X        listit (linecopy, lc, (Word *)&temp, 2*count);
  1235. X        for (i = 0; i < count; i++) {
  1236. X            putoutbin ((Word *)&temp, 1);
  1237. X        }
  1238. X    }
  1239. X    lc += (2 * count);
  1240. X    return (0);
  1241. X}
  1242. X
  1243. X
  1244. Xint do_string ()
  1245. X{
  1246. X    Word buf[120], *bp;
  1247. X    Word delim;
  1248. X    int len, i;
  1249. X
  1250. X    if (label && *label)
  1251. X        insert (label, (long) lc, &o_none, curseg, NO);
  1252. X    delim = *opd++;
  1253. X    bp = buf;
  1254. X    while (*opd != delim) {
  1255. X        if (*opd != '\\')
  1256. X            *bp++ = *opd;
  1257. X        else {
  1258. X            ++opd;
  1259. X            *bp++ = escape (&opd);
  1260. X        }
  1261. X        opd++;
  1262. X    }
  1263. X    *bp++ = '\0';
  1264. X    len = bp - buf;
  1265. X    if (pass == 2) {
  1266. X        listit (linecopy, lc, buf, len);
  1267. X        putoutbin (buf, len);
  1268. X    }
  1269. X    lc += len;
  1270. X    return (0);
  1271. X}
  1272. X
  1273. X
  1274. @FUNKY STUFF~
  1275. echo extracting - asm.1
  1276. sed 's/^X//' > asm.1 << '@FUNKY STUFF~'
  1277. X.so /usr/lib/tmac/tmac.e
  1278. X.TH ASM 1 "1 May 1986"
  1279. X.SH NAME
  1280. Xasm \- generic assembler
  1281. X.SH SYNOPSIS
  1282. X.B asm
  1283. X[
  1284. X.B \-o
  1285. Xbinname] [
  1286. X.B \-l
  1287. Xlistname] [
  1288. X.B \-x
  1289. Xxrefname] inputfile
  1290. X.br
  1291. X.SH DESCRIPTION
  1292. XThe generic assembler is an attempt to build a quick-and-dirty meta-
  1293. Xassembler, with which code for several types of microcomputers can be
  1294. Xgenerated. It outputs absolute code in two passes, contains a minimum of
  1295. Xpseudo-ops, and is quasi-portable between micro types. The opcodes and
  1296. Xinstruction layout information is contained within tables, leaving the
  1297. Xcode unchanged from micro to micro. There has been no effort expended to
  1298. Xmake the assembler match any particular assembly format on the market, so
  1299. Xdon't expect any miracles there.
  1300. X
  1301. XThe statup options specify various files for input and output. The basic
  1302. Xoption is the name of the input file; normally it is suffixed by ".a",
  1303. Xalthough this is not necessary. If no file is given, then input is taken
  1304. Xfrom standard input. The
  1305. X.B \-o
  1306. Xoption introduces the name of the file to receive the binary
  1307. Xoutput. If the option does not exist, the binary goes to standard output
  1308. X(since the output is actually in ASCII format, it won't bolix your screen
  1309. Xif you forget).  If the option is not followed immediately by a filename,
  1310. Xthen the binary will be output to the input file name suffixed by ".o".
  1311. XThe format of the binary output is "Intel Standard Hexadecimal Format" and
  1312. Xis documented in the source code.
  1313. XThe
  1314. X.B \-l
  1315. Xoption similarly specifies the file for the assembly listing; if the
  1316. Xoption is not given, no listing is produced. If the option is alone, then
  1317. Xthe listing will go into the input file name suffixed with ".l". The
  1318. X.B \-x
  1319. Xoption specifies the file to receive the cross-reference; it defaults to
  1320. Xthe same filename as the listing, and is deleted if the option is not
  1321. Xgiven.
  1322. X.pp
  1323. XThe assembler boasts (or at least admits) the following features:
  1324. X.in +.5i
  1325. X.ip \(bu
  1326. XTwo pass, all labels are defined both forward and backward.
  1327. X.ip \(bu
  1328. XAbsolute format code only, no relocation information available.
  1329. X.ip \(bu
  1330. XTable driven instruction formats, including single opcodes and fixed
  1331. Xnumbers of operands.
  1332. X.ip \(bu
  1333. XExpression evaluation in operands is left-to-right, no precedence or
  1334. Xparentheses.
  1335. X.ip \(bu
  1336. XPredefined symbols accomodated.
  1337. X.ip \(bu
  1338. XInstructions formats that vary with the size of certain of their operands
  1339. Xare accomodated, with some restrictions.
  1340. X.ip \(bu
  1341. XPseudo-ops include org, equ, set (for changing manifest variables), bss,
  1342. Xdata, data2 (two bytes!!), string, seg (for setting up data segments that
  1343. Xare made contiguous right after pass 1)
  1344. Xand end.
  1345. X.ip \(bu
  1346. XAtoms in operands include labels, ops add (+), subtract (-), multiply (*),
  1347. Xinteger divide (/), mod (%), and (&), or (|), and exclusive or (^),
  1348. Xdecimal constants, hexadecimal constants (with a leading zero), right
  1349. Xjustified zero-filled single characters ('x) and double characters ("xx).
  1350. XThe string pseudo-op supports strings surrounded by any unused delimiter.
  1351. X.in -.5i
  1352. X.pp
  1353. XThe pseudo op syntax is as follows:
  1354. X.in +.5i
  1355. X.ip "[label] org     expr
  1356. XSet the value of the symbol in label to the current location counter; set
  1357. Xthe location counter to the value of the expression.
  1358. X.ip "label   equ     expr
  1359. XSet the value of the symbol in label to the value of the expression. Any
  1360. Xsuch value may only be changed by a "set" pseudo.
  1361. X.ip "label   set     expr
  1362. XReset the value of a symbol to the value of the expression.
  1363. X.ip "[label] bss     expr
  1364. XSet the value of the symbol in the label to the current location counter,
  1365. Xthen set the location counter to its current value plus the value of the
  1366. Xexpression.
  1367. X.ip "[label] data    [:count:]expr
  1368. XSet the value of the label to the current location counter, and then
  1369. Xgenerate count (default 1) bytes of data, each containing the value of the
  1370. Xexpression. Count must contain no forward referenced symbols.
  1371. X.ip "[label] data2   [:count:]expr
  1372. XSet the value of the label to the current location counter, and then
  1373. Xgenerate count (default 1) double-bytes of data, each double-byte
  1374. Xcontaining the value of the expression.
  1375. XCount must contain no forward referenced symbols.
  1376. X.ip "[label] string  $string$
  1377. XSet the value of the label to the current location counter, and then
  1378. Xgenerate the string as bytes from left to right, appending a single nul
  1379. Xbyte. The string delimiter shown above ($) may be any character that
  1380. Xdoesn't appear in the string itself, except blank or tab. The special
  1381. Xescapes \\t (tab), \\r (carriage return), \\n (newline), \\b (backspace),
  1382. X\\? (del), \\^ (escape), \\nn (nn is any hex pair) and \\\\ (\\ itself)
  1383. Xare allowed.
  1384. X.ip "    seg   [name]
  1385. XDeclare a new or reuse an older data segment, which defines it's own
  1386. Xlocation counter. The segment that is predefined at the beginning of the
  1387. Xassembler may be returned to by a
  1388. X.b seg
  1389. Xwith no argument.  Any number of segments may be invoked.  Each segment's
  1390. Xlocation counter starts at zero during pass 1. When pass 1 is complete,
  1391. Xthe segments are "stacked" in the order that they were created, so that
  1392. Xthe second segment's lc starts at the first location following the end of
  1393. Xthe first segment's highest lc.  These computed lc's are displayed in the
  1394. Xpass 2 listing output.  The name used may be any non-blank-containing
  1395. Xstring; it is also independent of the symbol name space. At this time,
  1396. Xthere are no other definable characteristics of segments.
  1397. X.in -.5i
  1398. X.SH "MACHINES SUPPORTED
  1399. XWith this edition are included tables for the Motorola 6803 and 6809, the
  1400. XIntel 8085 and 6502.
  1401. X.SH "OTHER FILES
  1402. X/tmp/asm* - intermediate files.
  1403. X.SH AUTHOR
  1404. XLyle McElhaney
  1405. @FUNKY STUFF~
  1406. echo extracting - asm_ops.5
  1407. sed 's/^X//' > asm_ops.5 << '@FUNKY STUFF~'
  1408. X.so /usr/lib/tmac/tmac.e
  1409. X.TH ASM_OPS 5 "1 Nov 1986"
  1410. X.SH NAME
  1411. Xasm_ops \- generic assembler op-code tables
  1412. X.SH DESCRIPTION
  1413. XThe generic assembler
  1414. X.b asm
  1415. Xcan be made to assemble code for a number of different microprocessors. At
  1416. Xthe time of this writing, codes have been developed for the Intel 8085,
  1417. Xthe Motorola 6803, , the 6809 (with a lot of squeezing) and the 6502
  1418. X(Commodore 64). This manual page will describe the format of the ops.h
  1419. Xfile, which contains the processor-specific parts of the assembler.  The
  1420. Xstructures described below are defined in the file asm.h.
  1421. X
  1422. XThe opd.h file consists in a series of structure initializations, that
  1423. Xgenerate tables in the assembler when it is compiled.  Most of the lines
  1424. Xare of the form:
  1425. X
  1426. X    table-type name = {value, ....., value};
  1427. X
  1428. Xwhere the names are arbitrary (within the c-compiler naming restrictions)
  1429. Xand the values may be integers, Flags (i.e., boolean-valued integers),
  1430. Xstrings (actually pointers to strings), pointers to other structures
  1431. Xwithin the file, and pointers to functions in the assembler itself. The
  1432. Xtype Word refers an unsigned byte and Memad refers to a type holding any
  1433. Xpossible memory address for the target machine.  The type Acc refers to
  1434. Xthe accumulator used in computing expression values; make it unsigned
  1435. Xlong. If Acc is not 32 bits long, then some things will need changes,
  1436. Xparticularly the mask field in the opdef structure.
  1437. X
  1438. XThe first structure is opdclass, which defines the kinds of operands that
  1439. Xmay appear in an instruction, and their encoding in the corresponding
  1440. Xinstruction word:
  1441. X
  1442. X.nf
  1443. Xtypedef struct opdclassitem {   /* This defines an instruction field */
  1444. X    int length;                     /* length in bits of field */
  1445. X    Flag signed;                    /* else unsigned */
  1446. X    Flag byteswapped;               /* data has bytes backwards */
  1447. X    Flag relative;                  /* field is relative to $ */
  1448. X    int offset;                     /* fixed value added to field */
  1449. X} opdclass;
  1450. X.fi
  1451. X
  1452. XAn operand's
  1453. X.b length
  1454. Xrefers to the number of bits that are allocated for it
  1455. Xin the instruction field. If that number is eight, then only numbers from
  1456. X-128 through +127 (two's complement assumed) can fit in the field. If the
  1457. Xnext flag,
  1458. X.b signed ,
  1459. Xis set then the range becomes 0 through 255, in this
  1460. Xexample. The
  1461. X.b byteswapped
  1462. Xflag is set if the bytes (in a multibyte field)
  1463. Xare to be loaded within a 2 byte word in right-to-left order, rather then
  1464. Xthe more conventional left-to-right. The
  1465. X.b relative
  1466. Xflag is set if the value
  1467. Xto be placed in the field must first be decremented by the value of the
  1468. Xlocation counter before insertion. Finally,
  1469. X.b offset
  1470. Xis an integer value
  1471. Xto be added to the value of the field before it is inserted. As an
  1472. Xexample, an entry for the 6803 reads:
  1473. X
  1474. Xopdclass o_rmem  = { 8, YES, NO , YES, -2};
  1475. X
  1476. XThis defines a field that is used in relative-mode instructions. The field
  1477. Xis eight bits long, is signed, and is relative to the current lc. In
  1478. Xaddition, it is expected to be decremented by two. Given all this, the
  1479. Xlegal range of a value to be placed in this field must be from (lc)-126
  1480. Xthrough (lc)+129 inclusive, where (lc) is the current value of the
  1481. Xlocation counter (which points to the first byte of the current
  1482. Xinstruction).
  1483. X
  1484. XThe second "set" of structures, insclass, define an instruction type.
  1485. XEvery generated instruction must fall within one of these types.  They
  1486. Xdefine the instruction structure (as a collection of fields) and the
  1487. Xwritten form of its invocation:
  1488. X
  1489. X.nf
  1490. Xtypedef struct insclassitem {   /* This defines an instruction type */
  1491. X    int length;                     /* instruction length in bytes */
  1492. X    int mopds;                      /* number of operands expected */
  1493. X    opdclass *type[MAXOPDS];        /* each operand's field type */
  1494. X    int offset[MAXOPDS];            /* each operand's bit offset,
  1495. X                       from right end of first byte */
  1496. X} insclass;
  1497. X.fi
  1498. X
  1499. XThe
  1500. X.b length
  1501. Xof an instruction type is the number of bytes in the
  1502. Xinstruction, including all the fields.  The number of operands expected
  1503. X.b mopd
  1504. Xmay be 0, 1, or 2 (making this larger would involve changes to asm.h and
  1505. Xasm.c). MAXOPDS enforces the current limit on operands to two.  The
  1506. Xmembers of the array
  1507. X.btype
  1508. Xare pointers to the appropriate opdclass defined
  1509. Xabove.  When the instruction is scanned, the first operand must fit the
  1510. Xfield described in the structure pointed to be xxx.type[0], the second by
  1511. Xxxx.type[1]. The array
  1512. X.b offset
  1513. Xdefines the amount of shifting to be done to
  1514. Xproperly align the field in the instruction.  An offset of zero states
  1515. Xthat the field's rightmost bit should be placed in the rightmost bit of
  1516. Xthe instruction's first byte; a negative offset requires the value to be
  1517. Xshifted left that many bits, and a positive value must be shifted right.
  1518. XAn example, again from the 6803, shows the format of a relative
  1519. Xinstruction:
  1520. X
  1521. Xinsclass i_rel   = {2, 1, &o_rmem, &o_none,  8, 0};
  1522. X
  1523. XSuch an instruction is two bytes long, and contains one operand. This
  1524. Xoperand is a relative memory operand (from the example above), and it must
  1525. Xbe shifted to the right 8 bits (which puts it in the second byte of the
  1526. Xinstruction exactly). The second operand must have an address even though
  1527. Xits not used; o_none fills this requirement.
  1528. X
  1529. XAll this is leading, of course to the definition of individual
  1530. Xinstructions. These are defined in the opdef structures:
  1531. X
  1532. X.nf
  1533. Xtypedef struct opdefitem {      /* Defines an instruction */
  1534. X    char *name;                     /* instruction mnemonic */
  1535. X    insclass *class;                /* instruction type */
  1536. X    Acc mask;                       /* mask for first byte of instruction */
  1537. X    int (*action) ();               /* action routine for assembly */
  1538. X} opdef;
  1539. X.fi
  1540. X
  1541. XEach instruction has a
  1542. X.b name
  1543. Xthat is recognized during the source code
  1544. Xscanning. It also has a pointer to the insclass
  1545. X.b class
  1546. Xthat defines both what the
  1547. Xscanner should expect and how the finished instruction looks. The
  1548. X.b mask
  1549. Xis a value to be or'ed in with the assembled operand fields to complete the
  1550. Xinstruction. It normally contains the instruction-unique bits known as the
  1551. Xopcode. It is defined as an Acc type, and therefore the mask may exceed
  1552. Xthe size of the instruction. Assume the most significant bits are aligned
  1553. Xwhen assigning a value to
  1554. X.b mask .
  1555. XNote that this also limits the size of the mask (and the opcode-fixed bits of the
  1556. Xinstruction) to the length of Acc. This is true of all fields in the
  1557. Xinstruction; none may exceed the length of Acc in bits.
  1558. X
  1559. XFinally, the routine
  1560. X.b action
  1561. Xdefined to assemble the instruction
  1562. Xmust be given. For all normal instructions, the routine is
  1563. X.u geninstr ,
  1564. Xwhich generates all normal instructions from the table data. This field is
  1565. Xdefined primarily so that pseudo-ops can also use the structure.
  1566. X
  1567. XNow, the opdef table is defined in a slightly different way than the other
  1568. Xtables. The entries in the other tables are all referenced by pointers,
  1569. Xso their order is of no consequence.  The opdef table (named optab), on
  1570. Xthe other hand, must be searched by the assembler. Therefore, each entry
  1571. Xis a member of the array optab, and not a separate statement. The entries
  1572. Xin the table may be in no particular order, however, since the table is
  1573. Xsearched linearly for the nonce.
  1574. X
  1575. XAn example of a defined instruction for the 6803 is
  1576. X
  1577. X.nf
  1578. Xopdef optab [] =
  1579. X    ....
  1580. X    "bra"    , &i_rel  , 0x20000000, geninstr,
  1581. X    ....
  1582. X};
  1583. X.fi
  1584. X
  1585. XThe unconditional branch instruction has its format defined by the i_rel
  1586. Xclass of instruction formats (which, as shown above, defines a two byte
  1587. Xinstruction with one operand, etc.).  The mask for the first byte of the
  1588. Xinstruction (the opcode for a branch) is hex 20. It is generated by the
  1589. Xgeninstr routine. Note that the
  1590. X.b mask
  1591. Xfield is assumed to be 32 bits long, in this instance.
  1592. X
  1593. XWhat of the microprocessors that have two different instructions that may
  1594. Xbe used to perform an operation, such as the 6803 that can load a register
  1595. Xfrom a memory location with either a two byte relative instruction or a
  1596. Xthree byte extended instruction? The native assembler can generate the
  1597. Xshortest instruction that will fulfill the effect; so can the generic
  1598. Xassembler, under some circumstances. The third set of structures, called
  1599. Xchoicedef, is used in this case:
  1600. X
  1601. X.nf
  1602. Xtypedef struct chcitem {        /* Defines the alternatives for instr choices */
  1603. X    char *rname;                    /* restrictive mnemonic */
  1604. X    char *nname;                    /* non-restrictive mnemonic */
  1605. X    int field;                      /* operand that is restricted */
  1606. X    int lorange, hirange;           /* range of restriction inclusive */
  1607. X    Flag relative;                  /* to current lc, else absolute value */
  1608. X} choicedef;
  1609. X.fi
  1610. X
  1611. XAny choicedef that exists (there may be none, if the microprocessor has no
  1612. Xsuch overlapping instructions) describes the tradeoff to be made. The
  1613. X.b rname
  1614. Xis the mnemonic that may be used in the restrictive case of the
  1615. Xchoice (i.e., the one that is more desireable, usually leading to a
  1616. Xsmaller instruction).
  1617. X.b Nname
  1618. Xis the mnemonic to be used otherwise.
  1619. XPresumably, the two choices are mutually inclusive of all possibilities,
  1620. Xso that the nname mnemonic may be substituted in all cases to achieve the
  1621. Xdesired result. The field
  1622. X.b field
  1623. Xis either one or two, describing which
  1624. Xfield the choice hinges on. The
  1625. X.b lorange and
  1626. X.b hirange
  1627. Xvalues are the
  1628. Xinclusive limits of the values that the field must fall within in order to
  1629. Xqualify for the restrictive choice. Finally, the
  1630. X.b relative
  1631. Xflag states that
  1632. Xthe ranges are or are not relative to the current location counter. (At
  1633. Xthis point, the relative flag is not implemented.)
  1634. X
  1635. XThe infamous example:
  1636. X
  1637. X    "add"    , (insclass *)&c_add, 0x00, choiceinstr,
  1638. X
  1639. XThis entry in the optab table defines an pseudo instruction called add. It
  1640. Xmay be expanded as the instruction adds, if conditions are right, or as
  1641. Xaddz in any case. Instead of pointing to an instruction class, the second
  1642. Xentry in the structure is the address of a choice structure, which is cast
  1643. Xas an insclass pointer to keep c and lint happy. The mask is defaulted
  1644. X(its value is not used), and the generating routine is changed to
  1645. Xchoiceinstr, which handles the cases. The choicedef entry pointed to is:
  1646. X
  1647. Xchoicedef c_add = {"adds" , "addz" , 2, 0, 0xff, NO};
  1648. X
  1649. XThis defines a choice of either the adds instruction or the addz
  1650. Xinstruction to add a memory location to an accumulator. The second field,
  1651. Xthe memory reference, is the key: if the reference is greater than or equal
  1652. Xto zero, and less than or equal to hex ff (decimal 255), then adds can be
  1653. Xused; otherwise only addz is allowed.
  1654. X
  1655. XAs I said above, the choice mechanism is restricted in the decisions that
  1656. Xit can make in attempting to use the shortest instruction.  Since the
  1657. Xchoices are all made during the first pass, the expression in the deciding
  1658. Xfield must be completely backward-defined.  That means that all symbols in the
  1659. Xexpression must be either constants, be predefined (see below) or have
  1660. Xbeen defined in the code physically before the line where the choice
  1661. Xresides. In addition, all symbols in the expression must be in the same
  1662. Xsegment as the code being generated. This is not to say that using a
  1663. Xchoice instruction containing a forward reference is an error; rather, the
  1664. Xassembler, in the absence of required data to make the decision, will opt
  1665. Xfor the "otherwise" form of the instruction, when it could be possible to
  1666. Xuse the other. As Captain Kirk says, "Sie la vie."
  1667. X
  1668. XThe last set of entries in the ops.h file is a group of predefined symbols
  1669. Xthat the assembler "knows" about for all assemblies on this
  1670. Xmicroprocessor. An example of these definitions is:
  1671. X
  1672. X.nf
  1673. Xsymbol predef[] = {
  1674. X    {"ra"        ,    0x0, &o_reg  , (struct seg *)0 },
  1675. X    {"rb"        ,    0x1, &o_reg  , (struct seg *)0 },
  1676. X    {"eq"        ,    0x7, &o_cond , (struct seg *)0 },
  1677. X    {"nc"        ,    0x4, &o_cond , (struct seg *)0 },
  1678. X    {""          ,    0x0, &o_none , (struct seg *)0 },
  1679. X};
  1680. X.fi
  1681. X
  1682. XThese predefine the symbols ra, rb, eq, and nc for use in instructions
  1683. Xthat reference register a, register b, and the branch conditions eq and nc
  1684. X(no carry). Each is given a value, points to an operand type (which is not
  1685. Xcurrently used), and defined in the null segment (that is, the only
  1686. Xpredefined, default segment). Note the null entry at the end of the table.
  1687. X
  1688. XAfter all the tables a routine called "optional" must be defined. Optional
  1689. Xgets called whenever some non-lowercase or non-alphanumeric character is
  1690. Xencountered in the opcode field. when this happens, collection of the
  1691. Xopcode is terminated. After the rest of the instruction is fully encoded,
  1692. Xoptional gets called as:
  1693. X
  1694. X    optional (optop, obuf);
  1695. X
  1696. Xwhere optop is the string of characters that follow the opcode, and obuf is
  1697. Xan array of Words that contains the binary result of the instruction
  1698. Xassembly. Optional should modify obuf to achieve whatever results may be
  1699. Xdeemed necessary. If there are no requirements for changing the
  1700. Xinstruction at this point, then a null optional can be used:
  1701. X
  1702. X    optional (optop, obuf) Word *obuf; char *optop; {}
  1703. X
  1704. XNow, given the above description it should be possible to define an ops.h
  1705. Xfile to generate an assembler for most any machine. This scheme should
  1706. Xwork for almost any 8 or 16 bit microprocessor, although its only been
  1707. Xused with eights. Restrictions are enforced by the use of a long
  1708. Xvariable for expression solution and for instruction compilation, and
  1709. Xprobably other things that will become apparant when the assembler is
  1710. Xported to some wierd machine.
  1711. X
  1712. XChoices for instruction format are arbitrary, of course. I use a branch
  1713. Xconditional instruction with the conditional code as an operand to reduce
  1714. Xthe size of the optab (simply laziness); it would be easy to have
  1715. Xindividual branch instructions instead.
  1716. X
  1717. XFor the truely adventurous, I have put together a very simple macro
  1718. Xprocessor to ease the pain of putting together tables for the more
  1719. Xcomplicated machines. The 6809, for example, has many instructions that
  1720. Xare of identical format, the only differences being in the constant mask
  1721. Xpart of the op definition. (On the 6809, the memory reference instructions
  1722. Xadd, adc, bit, sub, cmp, and so on; the various forms of the cmpy and cmpu
  1723. Xinstructions form another similar group.) A pattern may be declared in the
  1724. XXXXX_ops.h file in the form:
  1725. X
  1726. X    beginpattern name
  1727. X    line......
  1728. X    another line...
  1729. X    endpattern
  1730. X
  1731. XThe lines in the pattern are invoked by the statement
  1732. X
  1733. X    pattern name,arg1,arg2
  1734. X
  1735. XThe strings arg1 and arg2 are substituted directly into the lines to
  1736. Xreplace the strings ~1 and ~2, respectively. That's all there is. Very
  1737. Xsimple, really. Look at 6809_ops.h for examples.
  1738. X
  1739. XExpansion of the macros is done by the program makeops.c. Making the
  1740. Xassembler, using the supplied makefile, will also build makeops, and
  1741. Xfilter XXXX_ops.h through it to get ops.h, which is included in the
  1742. Xcompilation of data.c.
  1743. @FUNKY STUFF~
  1744.