home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 149_01 / a68.c < prev    next >
Text File  |  1989-01-13  |  14KB  |  531 lines

  1. /*
  2.     HEADER:        CUG149;
  3.     TITLE:        6801 Cross-Assembler (Portable);
  4.     FILENAME:    A68.C;
  5.     VERSION:    3.5;
  6.     DATE:        08/27/1988;
  7.  
  8.     DESCRIPTION:    "This program lets you use your computer to assemble
  9.             code for the Motorola 6800, 6801, 6802, 6803, 6808,
  10.             and 68701 microprocessors.  The program is written in
  11.             portable C rather than BDS C.  All assembler features
  12.             are supported except relocation, linkage, and macros.";
  13.  
  14.     KEYWORDS:    Software Development, Assemblers, Cross-Assemblers,
  15.             Motorola, MC6800, MC6801;
  16.  
  17.     SEE-ALSO:    CUG113, 6800 Cross-Assembler;
  18.  
  19.     SYSTEM:        CP/M-80, CP/M-86, HP-UX, MSDOS, PCDOS, QNIX;
  20.     COMPILERS:    Aztec C86, Aztec CII, CI-C86, Eco-C, Eco-C88, HP-UX,
  21.             Lattice C, Microsoft C,    QNIX C;
  22.  
  23.     WARNINGS:    "This program has compiled successfully on 2 UNIX
  24.             compilers, 5 MSDOS compilers, and 2 CP/M compilers.
  25.             A port to BDS C would be extremely difficult, but see
  26.             volume CUG113.  A port to Toolworks C is untried."
  27.  
  28.     AUTHORS:    William C. Colley III;
  29. */
  30.  
  31. /*
  32.               6801 Cross-Assembler in Portable C
  33.  
  34.            Copyright (c) 1985 William C. Colley, III
  35.  
  36. Revision History:
  37.  
  38. Ver    Date        Description
  39.  
  40. 3.0    APR 1985    Recoded from BDS C version 2.5.  WCC3.
  41.  
  42. 3.1    AUG 1985    Greatly shortened the routines find_symbol() and
  43.             new_symbol().  Fixed bugs in expression evaluator.
  44.             Added compilation instructions for Aztec C86,
  45.             Microsoft C, and QNIX C.  Added optional optimizations
  46.             for 16-bit machines.  Adjusted structure members for
  47.             fussy compilers.  WCC3.
  48.  
  49. 3.2    SEP 1985    Added the INCL pseudo-op and associated stuff.  WCC3.
  50.  
  51. 3.3    JUL 1986    Added compilation instructions and tweaks for CI-C86,
  52.             Eco-C88, and Lattice C.  WCC3.
  53.  
  54. 3.4    JAN 1987    Fixed bug that made "FCB 0," legal syntax.  WCC3.
  55.  
  56. 3.5    AUG 1988    Fixed a bug in the command line parser that puts it
  57.             into a VERY long loop if the user types a command line
  58.             like "A68 FILE.ASM -L".  WCC3 per Alex Cameron.
  59.  
  60. This file contains the main program and line assembly routines for the
  61. assembler.  The main program parses the command line, feeds the source lines to
  62. the line assembly routine, and sends the results to the listing and object file
  63. output routines.  It also coordinates the activities of everything.  The line
  64. assembly routines uses the expression analyzer and the lexical analyzer to
  65. parse the source line and convert it into the object bytes that it represents.
  66. */
  67.  
  68. /*  Get global goodies:  */
  69.  
  70. #include "a68.h"
  71.  
  72. /*  Define global mailboxes for all modules:                */
  73.  
  74. char errcode, line[MAXLINE + 1], title[MAXLINE];
  75. int pass = 0;
  76. int eject, filesp, forwd, listhex;
  77. unsigned  address, bytes, errors, listleft, obj[MAXLINE], pagelen, pc;
  78. FILE *filestk[FILES], *source;
  79. TOKEN token;
  80.  
  81. /*  Mainline routine.  This routine parses the command line, sets up    */
  82. /*  the assembler at the beginning of each pass, feeds the source text    */
  83. /*  to the line assembler, feeds the result to the listing and hex file    */
  84. /*  drivers, and cleans everything up at the end of the run.        */
  85.  
  86. static int done, extend, ifsp, off;
  87.  
  88. void main(argc,argv)
  89. int argc;
  90. char **argv;
  91. {
  92.     SCRATCH unsigned *o;
  93.     int newline();
  94.     void asm_line();
  95.     void lclose(), lopen(), lputs();
  96.     void hclose(), hopen(), hputc();
  97.     void error(), fatal_error(), warning();
  98.  
  99.     printf("6800/6801 Cross-Assembler (Portable) Ver 3.5\n");
  100.     printf("Copyright (c) 1985 William C. Colley, III\n\n");
  101.  
  102.     while (--argc > 0) {
  103.     if (**++argv == '-') {
  104.         switch (toupper(*++*argv)) {
  105.         case 'L':   if (!*++*argv) {
  106.                 if (!--argc) { warning(NOLST);  break; }
  107.                 else ++argv;
  108.                 }
  109.                 lopen(*argv);
  110.                 break;
  111.  
  112.         case 'O':   if (!*++*argv) {
  113.                 if (!--argc) { warning(NOHEX);  break; }
  114.                 else ++argv;
  115.                 }
  116.                 hopen(*argv);
  117.                 break;
  118.  
  119.         default:    warning(BADOPT);
  120.         }
  121.     }
  122.     else if (filestk[0]) warning(TWOASM);
  123.     else if (!(filestk[0] = fopen(*argv,"r"))) fatal_error(ASMOPEN);
  124.     }
  125.     if (!filestk[0]) fatal_error(NOASM);
  126.  
  127.     while (++pass < 3) {
  128.     fseek(source = filestk[0],0L,0);  done = extend = off = FALSE;
  129.     errors = filesp = ifsp = pagelen = pc = 0;  title[0] = '\0';
  130.     while (!done) {
  131.         errcode = ' ';
  132.         if (newline()) {
  133.         error('*');
  134.         strcpy(line,"\tEND\n");
  135.         done = eject = TRUE;  listhex = FALSE;
  136.         bytes = 0;
  137.         }
  138.         else asm_line();
  139.         pc = word(pc + bytes);
  140.         if (pass == 2) {
  141.         lputs();
  142.         for (o = obj; bytes--; hputc(*o++));
  143.         }
  144.     }
  145.     }
  146.  
  147.     fclose(filestk[0]);  lclose();  hclose();
  148.  
  149.     if (errors) printf("%d Error(s)\n",errors);
  150.     else printf("No Errors\n");
  151.  
  152.     exit(errors);
  153. }
  154.  
  155. /*  Line assembly routine.  This routine gets expressions and tokens    */
  156. /*  from the source file using the expression evaluator and lexical    */
  157. /*  analyzer, respectively.  It fills a buffer with the machine code    */
  158. /*  bytes and returns nothing.                        */
  159.  
  160. static char label[MAXLINE];
  161. static int ifstack[IFDEPTH] = { ON };
  162.  
  163. static OPCODE *opcod;
  164.  
  165. void asm_line()
  166. {
  167.     SCRATCH int i;
  168.     int isalph(), popc();
  169.     OPCODE *find_code(), *find_operator();
  170.     void do_label(), flush(), normal_op(), pseudo_op();
  171.     void error(), pops(), pushc(), trash();
  172.  
  173.     address = pc;  bytes = 0;  eject = forwd = listhex = FALSE;
  174.     for (i = 0; i < BIGINST; obj[i++] = NOP);
  175.  
  176.     label[0] = '\0';
  177.     if ((i = popc()) != ' ' && i != '\n') {
  178.     if (isalph(i)) {
  179.         pushc(i);  pops(label);
  180.         if (find_operator(label)) { label[0] = '\0';  error('L'); }
  181.     }
  182.     else {
  183.         error('L');
  184.         while ((i = popc()) != ' ' && i != '\n');
  185.     }
  186.     }
  187.  
  188.     trash(); opcod = NULL;
  189.     if ((i = popc()) != '\n') {
  190.     if (!isalph(i)) error('S');
  191.     else {
  192.         pushc(i);  pops(token.sval);
  193.         if (!(opcod = find_code(token.sval))) error('O');
  194.     }
  195.     if (!opcod) { listhex = TRUE;  bytes = BIGINST; }
  196.     }
  197.  
  198.     if (opcod && opcod -> attr & ISIF) { if (label[0]) error('L'); }
  199.     else if (off) { listhex = FALSE;  flush();  return; }
  200.  
  201.     if (!opcod) { do_label();  flush(); }
  202.     else {
  203.     listhex = TRUE;
  204.     if (opcod -> attr & PSEUDO) pseudo_op();
  205.     else normal_op();
  206.     while ((i = popc()) != '\n') if (i != ' ') error('T');
  207.     }
  208.     source = filestk[filesp];
  209.     return;
  210. }
  211.  
  212. static void flush()
  213. {
  214.     while (popc() != '\n');
  215. }
  216.  
  217. static void do_label()
  218. {
  219.     SCRATCH SYMBOL *l;
  220.     SYMBOL *find_symbol(), *new_symbol();
  221.     void error();
  222.  
  223.     if (label[0]) {
  224.     listhex = TRUE;
  225.     if (pass == 1) {
  226.         if (!((l = new_symbol(label)) -> attr)) {
  227.         l -> attr = FORWD + VAL;
  228.         l -> valu = pc;
  229.         }
  230.     }
  231.     else {
  232.         if (l = find_symbol(label)) {
  233.         l -> attr = VAL;
  234.         if (l -> valu != pc) error('M');
  235.         }
  236.         else error('P');
  237.     }
  238.     }
  239. }
  240.  
  241. #define    NONUM        0
  242. #define    NEEDBYTE    1
  243. #define    HAVENUM        2
  244.  
  245. static void normal_op()
  246. {
  247.     SCRATCH int numctl;
  248.     SCRATCH unsigned attrib, opcode, operand;
  249.     unsigned expr();
  250.     TOKEN *lex();
  251.     void do_label(), error(), unlex();
  252.  
  253.     do_label();
  254.  
  255.     attrib = opcod -> attr;
  256.     bytes = 1;  opcode = opcod -> valu;  operand = 0;
  257.     if (extend && opcode == 0x8d) attrib |= DIROK;
  258.     numctl = NONUM;
  259.  
  260.     if (attrib & IS6801) {
  261.     attrib &= ~IS6801;
  262.     if (!extend) error('O');
  263.     }
  264.  
  265.     for (;;) {
  266.     switch (lex() -> attr & TYPE) {
  267.         case REG:    switch (token.valu) {
  268.                 case 'B':    if (opcode < 0x40) ++opcode;
  269.                     else opcode |= opcode < 0x80 ?
  270.                         0x10 : 0x40;
  271.  
  272.                 case 'A':    if (attrib & REGOPT) {
  273.                         attrib = NULL;  numctl = HAVENUM;
  274.                         break;
  275.                         }
  276.                     if (attrib & REGREQ) {
  277.                         attrib &= ~REGREQ;  break;
  278.                     }
  279.                     error('R');  bytes = 3;  return;
  280.  
  281.                 case 'X':    bytes = 3;
  282.                     if (!(attrib & INDEX)) {
  283.                         error('A');  return;
  284.                     }
  285.                     if (numctl == HAVENUM &&
  286.                         operand > 0xff) {
  287.                         error('V');  return;
  288.                     }
  289.                     bytes = 2;  numctl = NEEDBYTE;
  290.                     opcode = (opcode | 0x20) & 0xef;
  291.                     attrib &= REGREQ;  break;
  292.             }
  293.             if ((lex() -> attr & TYPE) != SEP) unlex();
  294.             break;
  295.  
  296.         case IMM:    bytes = 3;
  297.             if (!(attrib & (IMM16 + IMM8))) {
  298.                 error('A');  return;
  299.             }
  300.             operand = expr();
  301.             if (attrib & IMM8) {
  302.                 --bytes;
  303.                 if (operand > 0xff && operand < 0xff80) {
  304.                 error('V');  return;
  305.                 }
  306.             }
  307.             attrib &= REGREQ;  break;
  308.  
  309.         case OPR:
  310.         case STR:
  311.         case VAL:    unlex();
  312.             operand = expr();
  313.             if (attrib & REL) {
  314.                 numctl = HAVENUM;  bytes = 2;
  315.                 operand = word(operand - (pc + 2));
  316.                 if (operand > 0x7f && operand < 0xff80) {
  317.                 error('B');  return;
  318.                 }
  319.                 attrib = NULL;  break;
  320.             }
  321.  
  322.         case SEP:    bytes = 3;
  323.             if (numctl == NEEDBYTE) {
  324.                 if (operand > 0xff && operand < 0xff80) {
  325.                 error('V');  return;
  326.                 }
  327.                 numctl = HAVENUM;  bytes = 2;  break;
  328.             }
  329.             if (numctl == HAVENUM || !(attrib & INDEX)) {
  330.                 error('S');  return;
  331.             }
  332.             numctl = HAVENUM;  opcode |= 0x30;
  333.             attrib &= (INDEX + REGREQ + DIROK);
  334.             break;
  335.  
  336.         case EOL:    if (attrib & ~(DIROK + INDEX)) {
  337.                 error(attrib & REGREQ || (attrib & (REGOPT + INDEX)
  338.                 == (REGOPT + INDEX)) ? 'R' : 'S');
  339.                 bytes = 3;  return;
  340.             }
  341.             if (attrib & DIROK && !forwd && operand <= 0xff) {
  342.                 bytes = 2;  opcode ^= 0x20;
  343.             }
  344.  
  345.             obj[0] = opcode;
  346.             if (bytes == 2) obj[1] = low(operand);
  347.             if (bytes == 3) {
  348.                 obj[1] = high(operand);
  349.                 obj[2] = low(operand);
  350.             }
  351.             return;
  352.     }
  353.     }
  354. }
  355.  
  356. static void pseudo_op()
  357. {
  358.     SCRATCH char *s;
  359.     SCRATCH unsigned *o, u;
  360.     SCRATCH SYMBOL *l;
  361.     unsigned expr();
  362.     SYMBOL *find_symbol(), *new_symbol();
  363.     TOKEN *lex();
  364.     void do_label(), error(), fatal_error(), hseek(), unlex();
  365.  
  366.     o = obj;
  367.     switch (opcod -> valu) {
  368.     case CPU:   listhex = FALSE;  do_label();
  369.             u = expr();
  370.             if (forwd) error('P');
  371.             else if (u != 6800 && u != 6801) error('V');
  372.             else extend = u == 6801;
  373.             break;
  374.  
  375.     case ELSE:  listhex = FALSE;
  376.             if (ifsp) off = (ifstack[ifsp] = -ifstack[ifsp]) != ON;
  377.             else error('I');
  378.             break;
  379.  
  380.     case END:   do_label();
  381.             if (filesp) { listhex = FALSE;  error('*'); }
  382.             else {
  383.             done = eject = TRUE;
  384.             if (pass == 2 && (lex() -> attr & TYPE) != EOL) {
  385.                 unlex();  hseek(address = expr());
  386.             }
  387.             if (ifsp) error('I');
  388.             }
  389.             break;
  390.  
  391.     case ENDI:  listhex = FALSE;
  392.             if (ifsp) off = ifstack[--ifsp] != ON;
  393.             else error('I');
  394.             break;
  395.  
  396.     case EQU:   if (label[0]) {
  397.             if (pass == 1) {
  398.                 if (!((l = new_symbol(label)) -> attr)) {
  399.                 l -> attr = FORWD + VAL;
  400.                 address = expr();
  401.                 if (!forwd) l -> valu = address;
  402.                 }
  403.             }
  404.             else {
  405.                 if (l = find_symbol(label)) {
  406.                 l -> attr = VAL;
  407.                 address = expr();
  408.                 if (forwd) error('P');
  409.                 if (l -> valu != address) error('M');
  410.                 }
  411.                 else error('P');
  412.             }
  413.             }
  414.             else error('L');
  415.             break;
  416.  
  417.     case FCB:   do_label();
  418.             do {
  419.             if ((lex() -> attr & TYPE) == SEP) u = 0;
  420.             else {
  421.                 unlex();
  422.                 if ((u = expr()) > 0xff && u < 0xff80) {
  423.                 u = 0;  error('V');
  424.                 }
  425.             }
  426.             *o++ = low(u);  ++bytes;
  427.             } while ((token.attr & TYPE) == SEP);
  428.             break;
  429.  
  430.     case FCC:   do_label();
  431.             while ((lex() -> attr & TYPE) != EOL) {
  432.             if ((token.attr & TYPE) == STR) {
  433.                 for (s = token.sval; *s; *o++ = *s++)
  434.                 ++bytes;
  435.                 if ((lex() -> attr & TYPE) != SEP) unlex();
  436.             }
  437.             else error('S');
  438.             }
  439.             break;
  440.  
  441.     case FDB:   do_label();
  442.             do {
  443.             if ((lex() -> attr & TYPE) == SEP) u = 0;
  444.             else { unlex();  u = expr(); }
  445.             *o++ = high(u);  *o++ = low(u);
  446.             bytes += 2;
  447.             } while ((token.attr & TYPE) == SEP);
  448.             break;
  449.  
  450.     case IF:    if (++ifsp == IFDEPTH) fatal_error(IFOFLOW);
  451.             address = expr();
  452.             if (forwd) { error('P');  address = TRUE; }
  453.             if (off) { listhex = FALSE;  ifstack[ifsp] = NULL; }
  454.             else {
  455.             ifstack[ifsp] = address ? ON : OFF;
  456.             if (!address) off = TRUE;
  457.             }
  458.             break;
  459.  
  460.     case INCL:  listhex = FALSE;  do_label();
  461.             if ((lex() -> attr & TYPE) == STR) {
  462.             if (++filesp == FILES) fatal_error(FLOFLOW);
  463.             if (!(filestk[filesp] = fopen(token.sval,"r"))) {
  464.                 --filesp;  error('V');
  465.             }
  466.             }
  467.             else error('S');
  468.             break;
  469.  
  470.     case ORG:   u = expr();
  471.             if (forwd) error('P');
  472.             else {
  473.             pc = address = u;
  474.             if (pass == 2) hseek(pc);
  475.             }
  476.             do_label();
  477.             break;
  478.  
  479.     case PAGE:  listhex = FALSE;  do_label();
  480.             if ((lex() -> attr & TYPE) != EOL) {
  481.             unlex();  pagelen = expr();
  482.             if (pagelen > 0 && pagelen < 3) {
  483.                 pagelen = 0;  error('V');
  484.             }
  485.             }
  486.             eject = TRUE;
  487.             break;
  488.  
  489.     case RMB:   do_label();
  490.             u = word(pc + expr());
  491.             if (forwd) error('P');
  492.             else {
  493.             pc = u;
  494.             if (pass == 2) hseek(pc);
  495.             }
  496.             break;
  497.  
  498.     case SET:   if (label[0]) {
  499.             if (pass == 1) {
  500.                 if (!((l = new_symbol(label)) -> attr)
  501.                 || (l -> attr & SOFT)) {
  502.                 l -> attr = FORWD + SOFT + VAL;
  503.                 address = expr();
  504.                 if (!forwd) l -> valu = address;
  505.                 }
  506.             }
  507.             else {
  508.                 if (l = find_symbol(label)) {
  509.                 address = expr();
  510.                 if (forwd) error('P');
  511.                 else if (l -> attr & SOFT) {
  512.                     l -> attr = SOFT + VAL;
  513.                     l -> valu = address;
  514.                 }
  515.                 else error('M');
  516.                 }
  517.                 else error('P');
  518.             }
  519.             }
  520.             else error('L');
  521.             break;
  522.  
  523.     case TITL:  listhex = FALSE;  do_label();
  524.             if ((lex() -> attr & TYPE) == EOL) title[0] = '\0';
  525.             else if ((token.attr & TYPE) != STR) error('S');
  526.             else strcpy(title,token.sval);
  527.             break;
  528.     }
  529.     return;
  530. }
  531.