home *** CD-ROM | disk | FTP | other *** search
- /*
- X68 Motorola 6800 Cross Assembler June 1982
- For CP/M based computer systems
- (with lots of memory and big drives!)
- /*
- * PERMISSION IS GRANTED FOR THE PUBLIC DOMAIN
- * NON COMMERCIAL USE OF THIS SOFTWARE.
- *
- * (C) CHRIS UNDERY 25th OCTOBER 1982
- * 11 MARGARET ST NEWTOWN 2042
- * SYDNEY, AUSTRALIA
- */
-
- Chris Undery July 1982
- Peter Ansell Sept 1982
-
- Root Module: X68 Overlay loader & function library
-
- Overlay segments: X68SEG1 Pass 1
- X68SEG2 Pass 2
-
-
-
- */
-
- #include "x68.h" /* Global definitions file */
- #define OVERLAY_ADDRESS 0x3c00
-
- /* Assembler Main Control Loop */
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- int (*ptrfn) ();
- struct key *binary();
- struct nlist *lookup(), *install();
- char *tohex(), *getok();
- char *flush(), *purge(), * fault(), *smov();
- char *op(), *numops(), numargs(), *ev(), *evaluate(), *getsub();
- int cnum, todec(), getcomment();
- char command[12];
-
- ptrfn = OVERLAY_ADDRESS; /* Start of overlay RAM */
-
- printf("\nX68 M6800 Cross Assembler Version A.1 Sept 1982\n");
- if (argc < 2 ) {
- printf("USAGE: A>X68 Filename (options list)\n");
- exit();
- }
- strcpy(filename,argv[1]);
- clrsym(); /* Clear defaults and symbol table */
- if (!load()) /* Load mnemonics lookup table */
- exit();
- if ( argc >= 2 ) { /* There are some options to get */
- for (cnum = 2; cnum < argc ; cnum++ ) {
- strcpy(command,argv[cnum]);
- if (!parse(command)) exit();
- }
- }
- if (yanking) yankit(); /* Load an old symbol table */
- if (mloading) { /* Run Macro processor overlay */
- if (swapin("SEG3X68.OVL",OVERLAY_ADDRESS) != ERROR)
- (*ptrfn)(); /* Execute overlay */
- }
- if (swapin("SEG1X68.OVL",OVERLAY_ADDRESS) != ERROR)
- (*ptrfn)(); /* Execute overlay */
-
- else {
- printf("Aborting\n");
- exit();
- }
- if (swapin("SEG2X68.OVL",OVERLAY_ADDRESS) != ERROR)
- (*ptrfn)();
- else {
- printf("Aborting\n");
- exit();
- }
- if (syming) wrsym(); /* Dump symbol table to UFN.SYM */
- stats();
-
- }
-
- clrsym() /* Clear up the symbol bucket pointers */
- {
- int i;
- _allocp = NULL; /* Initialise memory allocator */
- for (i=0; i < HASHSIZE; i++) hashtab[i] = NULL;
- mloading = decad = lineno = useage = numlines = nb = dec = errors = 0;
- debug = listing = syming = yanking = 0; /* Default off on all options */
- numbytes = xing = printing = 0;
- strcpy(hexad,"0000"); /* Default to ORG zero */
- }
-
- hash(s) /* Calculate hash bucket start point for symbol */
- char *s;
- {
- int hashval;
-
- for (hashval = 0; *s != '\0'; )
- hashval += *s++;
- return(hashval % HASHSIZE);
- }
-
- struct nlist *lookup(s) /* Lookup symbol s in hashtab */
- char *s;
- {
- struct nlist *np;
-
- for (np = hashtab[hash(s)]; np != NULL; last = np, np = np->next)
- if (strcmp(s,np->name) == 0)
- return(np); /* found symbol */
- return(NULL);
- }
-
- struct nlist *install(nam,df) /* Put new symbol into table */
- char *nam, *df;
- {
- struct nlist *np, *lookup();
- char *strsave(), *alloc();
- int hashval;
-
- if ((np = lookup(nam)) == NULL) {
- np = alloc(sizeof(*np));
- if (np == NULL)
- return(NULL);
- if ((np->name = strsave(nam)) == NULL)
- return(NULL);
- hashval = hash(np->name);
- np->next = hashtab[hashval];
- hashtab[hashval] = np;
- useage += sizeof(*np); /* Keep statistics */
- } else /* already there */
- free(np->def); /* free previous definition */
- if ((np->def = strsave(df)) == NULL)
- return(NULL);
- return(np);
- }
-
-
- strsave(s) /* Save string in space obtained from dynamic store */
- {
- char *p;
-
- if ((p = alloc(strlen(s)+1)) != NULL)
- strcpy(p,s);
- return(p);
- }
-
- /* this function performs a binary search of the opcodes table */
- /* which was loaded from file OPCODES */
-
- struct key *binary(word)
- char *word;
- {
- int cond;
- int mid, high, low;
- char kludge; /* silly flag */
-
- kludge = (word[3] == ' ');
- if (kludge) {
- word[3] = word[4]; /* Move register to 3 */
- word[4] = NULL;
- }
- low = 0;
- high = NKEYS - 1;
- while (low <= high) {
- mid = (low + high) /2;
- if ((cond = strcmp(word,v[mid].keyword)) < 0)
- high = mid - 1;
- else if (cond > 0)
- low = mid + 1;
- else { /* Extract goodies from table */
- strcpy(inst,v[mid].hexcode);
- strcpy(dest,v[mid].use);
- m4[0] = word[3];
- if (m4[0] != 'A')
- if (m4[0] != 'B') m4[0] = NULL;
- if (kludge) { /* Restore to spaced mnem */
- word[4] = word[3];
- word[3] = ' ';
- word[5] = NULL;
- }
- return(1);
- }
- }
- return(NULL);
- }
-
- /* Load opcode lookup table, pre sorted to KEYTAB */
-
- load()
- {
- int i;
- char buffer[132], nem[BUFSIZ];;
- struct key *bb;
-
- i = 0;
- if (fopen("OPCODES",nem) == ERROR) {
- printf("The OPCODES file is missing !!\n");
- return(0);
- }
- while(fgets(buffer,nem)) {
- bb = &v[i++];
- sscanf(buffer,"%s\t%s\t%s\n",bb->keyword,bb->hexcode,bb->use);
- }
- fclose(nem);
- return(1);
- }
-
- /* Print assembly statistics */
-
- stats()
- {
- printf("\nAssembly complete: ");
- if (errors) printf("%d ERROR(S)\n",errors);
- else printf("no errors\n");
- printf("Source lines processed: %d\n",numlines);
- printf("Last address: %04xH\n",decad);
- printf("Code generated: %d bytes (dec)\n",numbytes);
- printf("Symbol table useage: %d bytes (dec)\n",useage);
- if (syming) printf("Symbol file %s created\n",symname);
- if (xing) printf("Hex file %s created with bias of %04xH\n",hexname,bias);
- if (listing) printf("Print file %s created\n",lstname);
- return(1);
- }
-
-
- /* Convert string representing number in BASE N */
-
- todec(ascii,base) /* Return val of base string */
- char *ascii, base;
- {
- unsigned val; /* will be result */
- char c;
-
- val = 0;
- if (_bc(_igs(&ascii),base) == ERROR ) return(0);
- while ((c = _bc(*ascii++,base)) != 255)
- val = val * base + c;
- ascii--;
- return(val);
- }
-
-
- /* Extract substring TOKEN from source string */
- /* place in destination string, and truncate */
- /* destination after WIDTH characters have moved */
-
- getok(token,from,fldnum,width)
- char *token, *from;
- int fldnum, width;
-
- {
- int i;
- char inquote; /* true if on quoted string */
-
- inquote = 0;
- fldnum--; /* Gives start occ of string to get */
- if (fldnum == 0) fldnum--; /* special case fld one */
- i = 0;
- while (i < fldnum) { /* Index along to fld start */
- if ((*from == TAB) || (*from == '\n')) i++;
- if (*from++ == '\0' ) {
- *token = NULL;
- return(0);
- }
- }
- while ((*from != TAB) && (*from != '\n')) {
- if (width-- == 0) {
- *token = '\0';
- return(1);
- }
- if (*from == 0x22 || *from == 0x27) inquote = (~ inquote);
- if (inquote) *token++ = *from++; /* dont alter quotes */
- else *token++ = toupper(*from++);
- }
- *token = '\0';
- }
-
- /* Scan string for comment delimiter and then move delimter */
- /* and everything following into destination string comment */
- /* ignore case of letters */
-
- getcomment(s) /* Get COMMENT FLD FROM LINE */
- char *s;
- {
- while (*s++ ) { /* search string to comment fld */
- if (*s == ';') {
- strcpy(comment,--s);
- return(1);
- }
- }
- strcpy(comment,"\n"); /* Terminate string with CRLF */
- return(0);
- }
-
-
- tohex(dst,s) /* Convert decimal to hex */
- char *dst;
- int s;
- {
- sprintf(dst,"%04x",s); /* 4 digit precision required */
- }
-
- smov(dest,source,num) /* MOV a string partial to dest string */
- char *dest, *source;
- int num;
- {
- while ((*dest++ = *source++) && (num-- != 0));
- *--dest = '\0';
- }
-
-
- parse(option) /* Parse the assembly time options */
- char *option;
- {
-
- if (*option != '-' ) { /* Invalid command format */
- printf("Bad option syntax: %s\n",option);
- return(0);
- }
- switch (option[1]) { /* now determine command */
- case 'Y': { yanking = 1; /* Yank symbol file before start */
- strcpy(symname,&option[2]);
- strcat(symname,".SYM");
- return(1);
- }
- case 'W': { syming = 1; /* Write symbol file at end */
- strcpy(symn,&option[2]);
- strcat(symn,":");
- strcat(symn,filename);
- strcat(symn,".SYM");
- return(1);
- }
- case 'L': { printing = 1; /* Output to list device */
- return(1);
- }
-
- case 'P': { strcpy(lstname,&option[2]);
- strcat(lstname,":"); /* drive name terminator */
- strcat(lstname,filename);
- strcat(lstname,".PRN");
- listing = 1;
- return(1); /* Create list file name */
- }
- case 'M': mloading = 1; /* Enable the pre-processor */
- return(1);
-
- case 'D': debug = 1; /* dont erase tmp file at end */
- return(1);
-
- case 'O': if (!ev(&option[2])) {
- printf("Cannot fwd ref on origin switch\n");
- exit();
- }
- tohex(hexad,dec); /* else convert result to hex */
- return(1);
-
- case 'H': xing = 1; /* Enable hex file output */
- strcpy(hexname,&option[2]);
- strcat(hexname,":");
- strcat(hexname,filename);
- strcat(hexname,".HEX");
- return(1);
- }
- printf("Bad option: <%c>\n",option[1]);
- return(0); /* force an abort */
- }
-
- /* Write Symbol Table to UFN.SYM */
- /* For later re-reading */
-
- wrsym() /* WRite symbol table */
- {
-
- char symb[BUFSIZ];
- struct nlist *tp, *lookup(); /* table pointers */
- int bucket, num; /* Bucket pointer */
-
- if (fcreat(symn,symb) == ERROR) { /* Cannot create */
- printf("Cannot create symbol file: DISK FULL\n");
- exit();
- }
- bucket = num = 0;
- while (bucket < HASHSIZE) { /* Loop through symbol table */
- for (tp = hashtab[bucket]; tp != NULL; tp = tp->next) {
- fprintf(symb,"%s\t%s\t\n",tp->def,tp->name);
- }
- bucket++; /* Next bucket */
- }
- putc(0x1a,symb); /* Close symbol file */
- fflush(symb);
- fclose(symb);
- return(1);
- }
-
- /* delete an entry from the symbol table */
-
- purge(symbol)
- char *symbol;
- {
- struct nlist **prev_link, *tp, *lookup();
- int bucket, num;
-
- bucket = num = 0;
- if ((tp = lookup(symbol)) == NULL) {
- printf("**WARNING: non existent symbol <%s> no purge\n");
- }
- else { /* remove this bugger from linked list */
- prev_link = last;
- *prev_link = tp->next;
- free(tp);
- useage -= sizeof(*tp);
- }
- return(1);
- }
-
- flush() /* flush all local symbols from the symbol table */
- {
-
- struct nlist *tp, **back;
- int bucket, num; /* Bucket pointer */
- char temp[10];
-
- bucket = num = 0;
- while (bucket < HASHSIZE) { /* Loop through symbol table */
- for (tp = hashtab[bucket]; tp != NULL; back = tp,tp = tp->next) {
- strcpy(temp,tp->def);
- if (temp[0] < 'A') { /* if graphic not alpha */
- *back = tp->next;
- useage -= sizeof(*tp);
- free(tp);
- }
- }
- bucket++; /* Next bucket */
- }
- return(1);
- }
-
- /* Load an old symbol file into the symbol table */
- /* to allow linkage to other modules */
-
- yankit() /* Load symbol file */
- {
- char *symbols, *install(); /* Structure pointers */
-
- if (fopen(symname,ibuf) == ERROR ) {
- printf("Cannot open: %s\n",symname);
- exit();
- }
- printf("Loading %s\n",symname); /* indicate doing something */
- while (fgets(temp,ibuf)) { /* Loop reading symbols */
- getok(hexad,temp,1,6);
- getok(label,temp,2,9); /* Extract from buffer */
- if ((symbols = install(label,hexad)) == NULL ) {
- printf("SYM FILE LOAD HAS BLOWN MY TABLE SPACE BOSS");
- exit();
- }
- }
- fclose(ibuf); /* Free up buffer for next overlay */
- }
-
-
- /* Calculate the number of operators in expression */
-
- numops(x) /* Get # of + - div mult */
- char *x;
- {
- int j;
-
- j = 0; /* default to no operators */
- while (*x) if (op(*x++)) j++;
- return(j);
- }
-
- op(c) /* Determine if character is operator */
- char c;
- {
- switch (c) { /* compare most common first for speed */
-
- case '+':
- case '-':
- case '/':
- case '*':
- case '%':
- case '>':
- case '<':
- case '|':
- case '&': return(1);
- break;
- default : return(0);
- }
- }
-
- numargs(s) /* Get # of commas in an expression */
- char *s; /* string address */
- {
- int i; /* Argument counter */
- i = 0;
- while (*s) if (*s++ == ',' ) i++;
- return(i+1); /* there is one more than num of , */
- }
-
- /* Evaluate left or right sub expression of a compound operand */
-
- ev(exp) /* Evaluate expression */
- char *exp;
- {
- int values[10], j, val, num;
- struct nlist *ep, *lookup(); /* Symbol table pointers */
-
- if (exp[0] == '$') { /* Location counter reference */
- dec = decad; /* Simple one */
- return(1);
- }
- if (exp[0] == '#') strcpy(subexp,&exp[1]);
- else
- strcpy(subexp,&exp[0]);
- if (isdigit(subexp[0])) { /* We have literal expression */
-
- j = strlen(subexp);
- switch (subexp[--j]) { /* Find Radix */
-
- case 'B': subexp[j] = NULL; /* Binary */
- dec = todec(subexp,2); /* Radix two */
- return(1);
-
- case 'O':
- case 'Q': subexp[j] = NULL; /* Octal */
- dec = todec(subexp,8);
- return(1);
-
- case 'H': subexp[j] = NULL; /* Hex */
- dec = todec(subexp,16);
- return(1);
-
- default: dec = todec(subexp,10); /* Decimal string */
- return(1);
- }
- } /* End of Numeric literals */
-
- if ((subexp[0] == 0x22) || (subexp[0] == 0x27)) { /* Quoted */
- dec = subexp[1]; /* Get ordinal value of char */
- return(1);
- }
- if ((ep = lookup(subexp)) == NULL ) return(0);
- dec = todec(ep->def,16); /* Convert symbol table entry to dec */
- return(1);
- }
-
- /* Evaluate the operand expression. It may be a simple or complex
- * expression. the function determines if the expression is complex
- * and if so, splits it into a left and right parts. the two parts
- * are then separately resolved and finally the they are combined via
- * a case switch on the operator . The evaluator can fail with invalid
- * result if an invalid literal is converted to decimal, as the _igs
- * function does not return a status indicating validity of the literal
- * ideally, the evaluator should not just peform a left right split as
- * this prevents it from handling expressions with more than two
- * components.. this is an area for much improvemment
- */
-
- evaluate(exp)
- char *exp; /* Expression pointer */
- {
- int acc1, acc2; /* Evaluation accumulators */
- char done, ops;
- char res1, res2; /* result of ev */
-
- ops = numops(exp); /* Find number of operators */
- if (ops == 0) return(ev(exp)); /* Normal simple expression */
- done = 0; /* Else here we go */
- acc1 = acc2 = xptr = 0; /* Clear accumulators */
-
- getsub(exp); /* Split left most two args */
- res1 =ev(xp1);
- acc1 = dec; /* up to caller to handle the problem */
- res2 = ev(xp2);
- acc2 = dec;
- switch (operator) { /* decide on operation */
-
- case '+' : acc1 += acc2; /* Addition */
- break;
- case '-' : acc1 -= acc2; /* Subtraction */
- break;
- case '/' : acc1 /= acc2; /* Division */
- break;
- case '*' : acc1 *= acc2; /* Multiplication */
- break;
- case '%' : acc1 %= acc2; /* Mod */
- break;
- case '<' : acc1 = (acc1 << acc2); /* shift left */
- break;
- case '>' : acc1 = (acc1 >> acc2); /* shift right */
- break;
- case '|' : acc1 = (acc1 | acc2); /* logical OR */
- break;
- case '&' : acc1 = (acc1 & acc2); /* logical AND */
- break;
-
- default : acc1 = 0;
- fault(1); /* invalid operator */
- res1 = 0;
- }
- dec = acc1;
- if ((!res1) || (!res2)) return(0);
- return(1); /* trap error in either argument */
- }
-
- /* Split the next two left most arguments from expression */
-
- getsub(x) /* Passed the address of operand */
- char x[];
- {
-
- int s;
-
- s = xptr = 0;
- while ((!op(x[s])) && (x[s] != ' ')) {
- s++;
- }
- smov(xp1,x,s);
- while (x[s] == ' ') s++;
- operator = x[s++]; /* Crank past op */
- while (x[s] == ' ') s++;
- smov(xp2,&x[s],10); /* found now copy */
- }
-
- fault(num) /* Inform carbon based unit of trouble */
- int num;
- {
- printf("**ERR: ");
- switch (num) { /* Print verbals */
-
- case 20: printf("Unknown mnemonic ");
- break;
- case 14: printf("Re-definition of %s ",label);
- break;
- case 23: printf("Bad addressing mode, %s %s",mnem,operand);
- break;
- case 210 : printf("Confused with %s %s %s ",label,mnem,operand);
- break;
- case 215 : printf("Bad literal %s ",operand);
- break;
- case 250:
- case 251: printf("Displacement out of range ");
- break;
- case 600: printf("Cannot evaluate operand ");
- break;
- case 1 : printf("Illegal operator in <%s> ",operand);
- break;
- }
-
- p_num: printf(" <%03d> at line %u in module %s\n",num,lineno,iname);
- printf("%s\n",line);
- errors++;
- fprintf(obuf,";** ERR: %02d ",num);
- fprintf(obuf,"PC: <%s> Mnem: <%s> Oprnd: <%s> ",labrec,mnem,operand);
- fprintf(obuf,"Class: <%c> I1: <%s> I2: <%s>",m4[0],i1,i2);
- fprintf(obuf,"I3: <%s>\n",i3);
-
- }
-