home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol140 / x68.c2 < prev    next >
Encoding:
Text File  |  1984-04-29  |  15.6 KB  |  664 lines

  1. /*
  2. X68    Motorola 6800 Cross Assembler         June 1982
  3.     For CP/M based computer systems
  4.     (with lots of memory and big drives!) 
  5. /*
  6.  *    PERMISSION IS GRANTED FOR THE PUBLIC DOMAIN
  7.  *    NON COMMERCIAL USE OF THIS SOFTWARE.
  8.  *
  9.  *    (C) CHRIS UNDERY 25th OCTOBER 1982
  10.  *    11 MARGARET ST NEWTOWN 2042
  11.  *    SYDNEY, AUSTRALIA
  12.  */
  13.  
  14.     Chris Undery July 1982
  15.     Peter Ansell Sept 1982
  16.     
  17.     Root Module:        X68 Overlay loader & function library
  18.  
  19.     Overlay segments:    X68SEG1  Pass 1
  20.                 X68SEG2  Pass 2
  21.  
  22.  
  23.  
  24. */
  25.  
  26. #include "x68.h"        /* Global definitions file    */
  27. #define OVERLAY_ADDRESS 0x3c00
  28.  
  29. /*    Assembler Main Control Loop    */
  30.  
  31. main(argc, argv)
  32. int argc;
  33. char **argv;
  34. {
  35.     int (*ptrfn) ();
  36.     struct key *binary();
  37.     struct nlist *lookup(), *install();
  38.     char *tohex(), *getok();
  39.     char *flush(), *purge(), * fault(), *smov();
  40.     char *op(), *numops(), numargs(), *ev(), *evaluate(), *getsub();
  41.     int cnum, todec(), getcomment();
  42.     char command[12];
  43.             
  44.     ptrfn = OVERLAY_ADDRESS;        /* Start of overlay RAM */
  45.     
  46.     printf("\nX68  M6800 Cross Assembler Version A.1     Sept 1982\n");
  47.     if (argc < 2 ) {
  48.         printf("USAGE: A>X68 Filename (options list)\n");
  49.         exit();
  50.     }
  51.     strcpy(filename,argv[1]);
  52.     clrsym();        /* Clear defaults and symbol table */
  53.     if (!load())         /* Load mnemonics lookup table    */
  54.         exit();
  55.     if ( argc >= 2 ) {    /* There are some options to get */
  56.         for (cnum = 2; cnum < argc ; cnum++ ) {
  57.             strcpy(command,argv[cnum]);
  58.             if (!parse(command)) exit();
  59.         }
  60.     }
  61.     if (yanking) yankit();    /* Load an old symbol table */
  62.     if (mloading) {        /* Run Macro processor overlay */
  63.         if (swapin("SEG3X68.OVL",OVERLAY_ADDRESS) != ERROR)
  64.         (*ptrfn)();    /* Execute overlay     */
  65.     }
  66.     if (swapin("SEG1X68.OVL",OVERLAY_ADDRESS) != ERROR)
  67.         (*ptrfn)();    /* Execute overlay    */
  68.  
  69.     else {
  70.         printf("Aborting\n");
  71.         exit();
  72.     }
  73.     if (swapin("SEG2X68.OVL",OVERLAY_ADDRESS) != ERROR)
  74.         (*ptrfn)();
  75.     else {
  76.         printf("Aborting\n");
  77.         exit();
  78.     }
  79.     if (syming) wrsym();    /* Dump symbol table to UFN.SYM */
  80.     stats();
  81.  
  82. }
  83.  
  84. clrsym()    /* Clear up the symbol bucket pointers    */
  85. {
  86.     int i;
  87.     _allocp = NULL;        /* Initialise memory allocator */
  88.     for (i=0; i < HASHSIZE; i++) hashtab[i] = NULL;
  89.     mloading = decad = lineno = useage = numlines = nb = dec = errors = 0;
  90.     debug = listing = syming = yanking = 0;    /* Default off on all options */
  91.     numbytes = xing = printing = 0;
  92.     strcpy(hexad,"0000");    /* Default to ORG zero */
  93. }
  94.  
  95. hash(s)        /* Calculate hash bucket start point for symbol */
  96. char *s;
  97. {
  98.     int hashval;
  99.  
  100.     for (hashval = 0; *s != '\0'; )
  101.         hashval += *s++;
  102.     return(hashval % HASHSIZE);
  103. }
  104.  
  105. struct nlist *lookup(s)            /* Lookup symbol s in hashtab */
  106. char *s;
  107. {
  108.     struct nlist *np;
  109.  
  110.     for (np = hashtab[hash(s)]; np != NULL; last = np,  np = np->next)
  111.         if (strcmp(s,np->name) == 0)
  112.             return(np);    /* found symbol    */
  113.     return(NULL);
  114. }
  115.  
  116. struct nlist *install(nam,df)        /* Put new symbol into table */
  117. char *nam, *df;
  118. {
  119.     struct nlist *np, *lookup();
  120.     char *strsave(), *alloc();
  121.     int hashval;
  122.  
  123.     if ((np = lookup(nam)) == NULL) {
  124.         np = alloc(sizeof(*np));
  125.         if (np == NULL)
  126.            return(NULL);
  127.         if ((np->name = strsave(nam)) == NULL)
  128.            return(NULL);
  129.         hashval = hash(np->name);
  130.         np->next = hashtab[hashval];
  131.         hashtab[hashval] = np;
  132.         useage += sizeof(*np);    /* Keep statistics */
  133.     } else            /* already there */
  134.         free(np->def);    /* free previous definition */
  135.     if ((np->def = strsave(df)) == NULL)
  136.         return(NULL);
  137.     return(np);
  138. }
  139.  
  140.  
  141. strsave(s)    /* Save string in space obtained from dynamic store */
  142. {
  143.     char *p;
  144.  
  145.     if ((p = alloc(strlen(s)+1)) != NULL)
  146.           strcpy(p,s);
  147.     return(p);
  148. }
  149.  
  150. /* this function performs a binary search of the opcodes table */
  151. /* which was loaded from file OPCODES */
  152.  
  153. struct key *binary(word)
  154. char *word;
  155. {
  156.     int cond;
  157.     int mid, high, low;
  158.     char kludge;        /* silly flag */
  159.     
  160.     kludge = (word[3] == ' ');
  161.     if (kludge) {
  162.         word[3] = word[4]; /* Move register to 3 */
  163.         word[4] = NULL;
  164.     }
  165.     low = 0;
  166.     high = NKEYS - 1;
  167.     while (low <= high) {
  168.         mid = (low + high) /2;
  169.         if ((cond = strcmp(word,v[mid].keyword)) < 0)
  170.             high = mid - 1;
  171.         else if (cond > 0)
  172.             low = mid + 1;
  173.         else {        /* Extract goodies from table */
  174.             strcpy(inst,v[mid].hexcode);
  175.             strcpy(dest,v[mid].use);
  176.             m4[0] = word[3];
  177.             if (m4[0] != 'A')
  178.               if (m4[0] != 'B') m4[0] = NULL;
  179.             if (kludge) { /* Restore to spaced mnem */
  180.                 word[4] = word[3];
  181.                 word[3] = ' ';
  182.                 word[5] = NULL;
  183.             }
  184.             return(1);
  185.         }
  186.     }
  187.     return(NULL);
  188. }
  189.  
  190. /*    Load opcode lookup table, pre sorted to KEYTAB */
  191.  
  192. load()
  193. {
  194.     int i;
  195.     char buffer[132], nem[BUFSIZ];;
  196.     struct key *bb;
  197.     
  198.     i = 0;
  199.     if (fopen("OPCODES",nem) == ERROR) {
  200.         printf("The OPCODES file is missing !!\n"); 
  201.         return(0);
  202.     }
  203.     while(fgets(buffer,nem)) { 
  204.           bb = &v[i++];
  205.       sscanf(buffer,"%s\t%s\t%s\n",bb->keyword,bb->hexcode,bb->use);
  206.     }
  207.     fclose(nem);
  208.     return(1);
  209. }
  210.  
  211. /*    Print assembly statistics */
  212.  
  213. stats()
  214. {
  215.     printf("\nAssembly complete: ");
  216.     if (errors) printf("%d ERROR(S)\n",errors);
  217.     else printf("no errors\n");
  218.     printf("Source lines processed: %d\n",numlines);
  219.     printf("Last address: %04xH\n",decad);
  220.     printf("Code generated: %d bytes (dec)\n",numbytes);
  221.     printf("Symbol table useage: %d bytes (dec)\n",useage);
  222.     if (syming) printf("Symbol file %s created\n",symname);
  223.     if (xing) printf("Hex file %s created with bias of %04xH\n",hexname,bias);
  224.     if (listing) printf("Print file %s created\n",lstname);
  225.     return(1);
  226. }
  227.  
  228.  
  229. /* Convert string representing number in BASE N */
  230.  
  231. todec(ascii,base)        /* Return val of base string */
  232. char *ascii, base;
  233. {
  234.     unsigned val;        /* will be result */
  235.     char c;
  236.  
  237.     val = 0;
  238.     if (_bc(_igs(&ascii),base) == ERROR ) return(0);
  239.     while ((c = _bc(*ascii++,base)) != 255)
  240.         val = val * base + c;
  241.     ascii--;
  242.     return(val);
  243. }
  244.  
  245.  
  246. /*    Extract substring TOKEN from source string    */
  247. /*    place in destination string, and truncate     */
  248. /*    destination after WIDTH characters have moved    */
  249.  
  250. getok(token,from,fldnum,width)
  251. char *token, *from;
  252. int fldnum, width;
  253.  
  254. {
  255.     int i;
  256.     char inquote;        /* true if on quoted string */
  257.  
  258.     inquote = 0;
  259.     fldnum--;        /* Gives start occ of string to get */
  260.     if (fldnum == 0) fldnum--;    /* special case fld one */
  261.     i = 0;
  262.     while (i < fldnum) {    /* Index along to fld start    */
  263.         if ((*from == TAB) || (*from == '\n')) i++;
  264.         if (*from++ == '\0' ) {
  265.             *token = NULL;
  266.             return(0);
  267.         }
  268.     }
  269.     while ((*from != TAB) && (*from != '\n')) {
  270.         if (width-- == 0) {
  271.             *token = '\0';
  272.             return(1);
  273.         }
  274.         if (*from == 0x22 || *from == 0x27) inquote = (~ inquote);
  275.         if (inquote) *token++ = *from++; /* dont alter quotes */
  276.         else *token++ = toupper(*from++);
  277.     }    
  278.     *token = '\0';
  279. }
  280.  
  281. /*    Scan string for comment delimiter and then move delimter */
  282. /*    and everything following into destination string comment */
  283. /*    ignore case of letters */
  284.  
  285. getcomment(s)            /* Get COMMENT FLD FROM LINE */
  286. char *s;
  287. {
  288.     while (*s++ ) {        /* search string to comment fld */
  289.         if (*s == ';') {
  290.             strcpy(comment,--s);
  291.             return(1);
  292.         }
  293.     }
  294.     strcpy(comment,"\n");    /* Terminate string with CRLF */
  295.     return(0);
  296. }
  297.  
  298.  
  299. tohex(dst,s)            /* Convert decimal to hex */
  300. char *dst;
  301. int s;
  302. {
  303.     sprintf(dst,"%04x",s);    /* 4 digit precision required */
  304. }
  305.  
  306. smov(dest,source,num)    /* MOV a string partial to dest string */
  307. char *dest, *source;
  308. int num;
  309. {
  310.     while ((*dest++ = *source++) && (num-- != 0));
  311.     *--dest = '\0';
  312. }
  313.  
  314.  
  315. parse(option)    /* Parse the assembly time options */
  316. char *option;
  317. {
  318.  
  319.     if (*option != '-' ) {        /* Invalid command format */
  320.         printf("Bad option syntax: %s\n",option);
  321.         return(0);
  322.     }
  323.     switch (option[1])  {        /* now determine command */
  324.     case 'Y': { yanking = 1;    /* Yank symbol file before start */
  325.             strcpy(symname,&option[2]);
  326.             strcat(symname,".SYM");
  327.             return(1);
  328.         }
  329.     case 'W': { syming = 1;        /* Write symbol file at end */
  330.             strcpy(symn,&option[2]);
  331.             strcat(symn,":");
  332.             strcat(symn,filename);
  333.             strcat(symn,".SYM");
  334.             return(1);
  335.         }
  336.     case 'L': { printing = 1;    /* Output to list device */
  337.             return(1);
  338.         }
  339.     
  340.     case 'P': { strcpy(lstname,&option[2]);
  341.             strcat(lstname,":"); /* drive name terminator */
  342.             strcat(lstname,filename);
  343.             strcat(lstname,".PRN");
  344.             listing = 1;
  345.             return(1);        /* Create list file name */
  346.         }
  347.     case 'M': mloading = 1;        /* Enable the pre-processor */
  348.           return(1);
  349.  
  350.     case 'D': debug = 1;        /* dont erase tmp file at end */
  351.           return(1);
  352.  
  353.     case 'O': if (!ev(&option[2])) {
  354.             printf("Cannot fwd ref on origin switch\n");
  355.             exit();
  356.           }
  357.           tohex(hexad,dec); /* else convert result to hex */
  358.           return(1);
  359.  
  360.     case 'H': xing = 1;        /* Enable hex file output */
  361.           strcpy(hexname,&option[2]);
  362.           strcat(hexname,":");
  363.           strcat(hexname,filename);
  364.           strcat(hexname,".HEX");
  365.           return(1);
  366.     }
  367.     printf("Bad option: <%c>\n",option[1]);
  368.     return(0);            /* force an abort */
  369. }
  370.  
  371. /*    Write Symbol Table to UFN.SYM        */
  372. /*    For later re-reading            */
  373.  
  374. wrsym()            /* WRite symbol table */
  375. {
  376.  
  377.     char symb[BUFSIZ];
  378.     struct nlist *tp, *lookup();        /* table pointers */
  379.     int bucket, num;                /* Bucket pointer */
  380.  
  381.     if (fcreat(symn,symb) == ERROR) {    /* Cannot create */
  382.         printf("Cannot create symbol file: DISK FULL\n");
  383.         exit();
  384.     }
  385.     bucket = num = 0;
  386.     while (bucket < HASHSIZE) {    /* Loop through symbol table */
  387.         for (tp = hashtab[bucket]; tp != NULL; tp = tp->next) {
  388.             fprintf(symb,"%s\t%s\t\n",tp->def,tp->name);
  389.         }
  390.     bucket++;            /* Next bucket */
  391.     }
  392.     putc(0x1a,symb);        /* Close symbol file */
  393.     fflush(symb);
  394.     fclose(symb);
  395.     return(1);
  396. }
  397.  
  398. /* delete an entry from the symbol table */
  399.  
  400. purge(symbol)
  401. char *symbol;
  402. {
  403.     struct nlist **prev_link, *tp, *lookup();
  404.     int bucket, num;
  405.  
  406.     bucket = num = 0;
  407.     if ((tp = lookup(symbol)) == NULL) {
  408.         printf("**WARNING: non existent symbol <%s> no purge\n");
  409.     }
  410.     else {        /* remove this bugger from linked list */
  411.         prev_link = last;
  412.         *prev_link = tp->next;
  413.         free(tp);
  414.         useage -= sizeof(*tp);
  415.     }
  416.     return(1);
  417. }
  418.  
  419. flush()        /* flush all local symbols from the symbol table */
  420. {
  421.  
  422.     struct nlist *tp, **back;
  423.     int bucket, num;                /* Bucket pointer */
  424.     char temp[10];
  425.  
  426.     bucket = num = 0;
  427.     while (bucket < HASHSIZE) {    /* Loop through symbol table */
  428.         for (tp = hashtab[bucket]; tp != NULL; back = tp,tp = tp->next) {
  429.             strcpy(temp,tp->def);
  430.             if (temp[0] < 'A') {    /* if graphic not alpha */
  431.                *back = tp->next;
  432.                useage -= sizeof(*tp);
  433.                free(tp);
  434.             }
  435.         }
  436.     bucket++;            /* Next bucket */
  437.     }
  438.     return(1);
  439. }
  440.  
  441. /*    Load an old symbol file into the symbol table */
  442. /*    to allow linkage to other modules        */
  443.  
  444. yankit()        /* Load symbol file */
  445. {
  446.     char  *symbols, *install(); /* Structure pointers */
  447.     
  448.     if (fopen(symname,ibuf) == ERROR ) {
  449.         printf("Cannot open: %s\n",symname);
  450.         exit();
  451.     }
  452.     printf("Loading %s\n",symname);    /* indicate doing something */
  453.     while (fgets(temp,ibuf)) {    /* Loop reading symbols */
  454.         getok(hexad,temp,1,6);
  455.         getok(label,temp,2,9);    /* Extract from buffer */
  456.         if ((symbols = install(label,hexad)) == NULL ) {
  457.             printf("SYM FILE LOAD HAS BLOWN MY TABLE SPACE BOSS");
  458.             exit();
  459.         }
  460.     }
  461.     fclose(ibuf);    /* Free up buffer for next overlay */
  462. }
  463.  
  464.  
  465. /*    Calculate the number of operators in expression */
  466.  
  467. numops(x)            /* Get # of + - div mult */
  468. char *x;
  469. {
  470.     int  j;
  471.  
  472.     j = 0;            /* default to no operators */
  473.     while (*x) if (op(*x++)) j++;
  474.     return(j);
  475. }
  476.  
  477. op(c)                /* Determine if character is operator */
  478. char c;
  479. {
  480.     switch (c) {        /* compare most common first for speed */
  481.         
  482.         case '+':
  483.         case '-':
  484.         case '/':
  485.         case '*':
  486.         case '%':
  487.         case '>':
  488.         case '<':
  489.         case '|':
  490.         case '&': return(1);
  491.               break;
  492.         default : return(0);
  493.     }
  494. }
  495.  
  496. numargs(s)            /* Get # of commas in an expression */
  497. char *s;    /* string address */
  498. {
  499.     int i;            /* Argument counter */
  500.     i = 0;
  501.     while (*s) if (*s++ == ',' ) i++;
  502.     return(i+1);        /* there is one more than num of , */
  503. }
  504.  
  505. /* Evaluate left or right sub expression of a compound operand */
  506.  
  507. ev(exp)            /* Evaluate expression */
  508. char *exp;
  509. {
  510.     int values[10], j, val, num;
  511.     struct nlist *ep, *lookup(); /* Symbol table pointers */
  512.  
  513.     if (exp[0] == '$') {        /* Location counter reference */
  514.         dec = decad;        /* Simple one */
  515.         return(1);
  516.     }
  517.     if (exp[0] == '#') strcpy(subexp,&exp[1]);
  518.     else 
  519.         strcpy(subexp,&exp[0]);
  520.     if (isdigit(subexp[0])) {    /* We have literal expression */
  521.  
  522.         j = strlen(subexp);
  523.         switch (subexp[--j]) {    /* Find Radix */    
  524.     
  525.         case 'B':    subexp[j] = NULL; /* Binary */
  526.                 dec = todec(subexp,2); /* Radix two */
  527.                 return(1);
  528.             
  529.         case 'O':
  530.         case 'Q':    subexp[j] = NULL; /* Octal */
  531.                 dec = todec(subexp,8);
  532.                 return(1);
  533.  
  534.         case 'H':    subexp[j] = NULL; /* Hex */
  535.                 dec = todec(subexp,16);
  536.                 return(1);
  537.         
  538.         default:    dec = todec(subexp,10); /* Decimal string */
  539.                 return(1);
  540.         } 
  541.     }         /* End of Numeric literals */
  542.  
  543.     if ((subexp[0] == 0x22) || (subexp[0] == 0x27)) { /* Quoted */
  544.         dec = subexp[1];    /* Get ordinal value of char */
  545.         return(1);
  546.     }
  547.     if ((ep = lookup(subexp)) == NULL ) return(0);
  548.     dec = todec(ep->def,16); /* Convert symbol table entry to dec */
  549.     return(1);
  550. }
  551.  
  552. /* Evaluate the operand expression. It may be a simple or complex 
  553.  * expression. the function determines if the expression is complex
  554.  * and if so, splits it into a left and right parts. the two parts 
  555.  * are then separately resolved and finally the they are combined via
  556.  * a case switch on the operator . The evaluator can fail with invalid
  557.  * result if an invalid literal is converted to decimal, as the _igs
  558.  * function does not return a status indicating validity of the literal
  559.  * ideally, the evaluator should not just peform a left right split as
  560.  * this prevents it from handling expressions with more than two 
  561.  * components.. this is an area for much improvemment
  562.  */
  563.  
  564. evaluate(exp)
  565. char *exp;        /* Expression pointer */
  566. {
  567.     int acc1, acc2;            /* Evaluation accumulators */
  568.     char done, ops;
  569.     char res1, res2;        /* result of ev */
  570.  
  571.     ops = numops(exp);        /* Find number of operators */
  572.     if (ops == 0) return(ev(exp));    /* Normal simple expression */
  573.     done = 0;            /* Else here we go */
  574.     acc1 = acc2 = xptr = 0;        /* Clear accumulators */
  575.  
  576.     getsub(exp);    /* Split left most two args */
  577.     res1 =ev(xp1);
  578.     acc1 = dec;    /* up to caller to handle the problem */
  579.     res2 = ev(xp2);
  580.     acc2 = dec;
  581.     switch (operator) {    /* decide on operation */
  582.             
  583.         case '+' : acc1 +=  acc2; /* Addition */
  584.                break;
  585.         case '-' : acc1 -=  acc2; /* Subtraction */
  586.                break;
  587.         case '/' : acc1 /=  acc2; /* Division */
  588.                break;
  589.         case '*' : acc1 *=  acc2; /* Multiplication */
  590.                break;
  591.         case '%' : acc1 %=  acc2; /* Mod */
  592.                break;
  593.         case '<' : acc1 = (acc1 << acc2); /* shift left */
  594.                break;
  595.         case '>' : acc1 = (acc1 >> acc2); /* shift right */
  596.                break;
  597.         case '|' : acc1 = (acc1 | acc2);  /* logical OR */
  598.                break;
  599.         case '&' : acc1 = (acc1 & acc2);  /* logical AND */
  600.                break;
  601.  
  602.         default  : acc1 = 0;
  603.                fault(1);    /* invalid operator */
  604.                res1 = 0;
  605.     }
  606.     dec = acc1;
  607.     if ((!res1) || (!res2)) return(0);
  608.     return(1);    /* trap error in either argument */
  609. }
  610.  
  611. /*    Split the next two left most arguments from expression */
  612.  
  613. getsub(x)            /* Passed the address of operand */
  614. char x[];
  615. {
  616.  
  617.     int s;
  618.  
  619.     s = xptr = 0;
  620.     while ((!op(x[s])) && (x[s] != ' ')) {
  621.          s++;
  622.     }
  623.     smov(xp1,x,s);
  624.     while (x[s] == ' ') s++;
  625.     operator = x[s++];    /* Crank past op */
  626.     while (x[s] == ' ') s++;
  627.     smov(xp2,&x[s],10);    /* found now copy */
  628. }
  629.  
  630. fault(num)        /* Inform carbon based unit of trouble */
  631. int num;
  632. {
  633.     printf("**ERR: ");
  634.     switch (num) {            /* Print verbals     */
  635.  
  636.         case 20: printf("Unknown mnemonic ");
  637.              break;
  638.             case 14: printf("Re-definition of %s ",label);
  639.              break;
  640.         case 23: printf("Bad addressing mode, %s %s",mnem,operand);
  641.              break;
  642.         case 210 : printf("Confused with %s %s %s ",label,mnem,operand);
  643.              break;
  644.         case 215 : printf("Bad literal %s ",operand);
  645.              break;
  646.         case 250:
  647.         case 251: printf("Displacement out of range ");
  648.              break;
  649.         case 600: printf("Cannot evaluate operand ");
  650.             break;
  651.         case 1  : printf("Illegal operator in <%s> ",operand);
  652.             break;
  653.         }
  654.  
  655. p_num:    printf(" <%03d> at line %u in module %s\n",num,lineno,iname);
  656.     printf("%s\n",line);
  657.     errors++;
  658.     fprintf(obuf,";** ERR: %02d ",num);
  659.      fprintf(obuf,"PC: <%s> Mnem: <%s> Oprnd: <%s> ",labrec,mnem,operand);
  660.     fprintf(obuf,"Class: <%c> I1: <%s> I2: <%s>",m4[0],i1,i2);
  661.     fprintf(obuf,"I3: <%s>\n",i3);
  662.     
  663. }
  664.