allbery@ncoast.UUCP (05/27/87)
Here is the source for a Z-80 cross assembler for Unix. I didn't write it. It was posted to net.sources previously, but I've sped it up and cleaned it up considerably. I hope it is useful to someone. I have successfully used it to compile assembler generated by Small-C, until my CP/M machine broke down. Ken #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # Makefile # as81.c # as82.c # as83.c # as85.c # asm.c # asm.h # asm80.1 # asm80.doc # This archive created: Wed May 27 04:10:53 1987 # By: Ken Yap () export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'Makefile'" '(209 characters)' if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # @(#)makefile 1.1 # CFLAGS=-O asm80: asm.o as81.o as82.o as83.o as85.o cc $(CFLAGS) asm.o as81.o as82.o as83.o as85.o -o asm80 asm.o: asm.h as81.o: asm.h as82.o: asm.h as83.o: asm.h as85.o: asm.h SHAR_EOF if test 209 -ne "`wc -c < 'Makefile'`" then echo shar: "error transmitting 'Makefile'" '(should have been 209 characters)' fi fi echo shar: "extracting 'as81.c'" '(5430 characters)' if test -f 'as81.c' then echo shar: "will not over-write existing file 'as81.c'" else cat << \SHAR_EOF > 'as81.c' /* * as81.c * Assemble a line. */ #include <stdio.h> #include "asm.h" #ifndef lint static char *sccsid="@(#)as81.c 1.3"; #endif extern int mkobj, nflag; /* * Assemble a line. */ asmline() { register struct sym *sp,*lsp; register int rs, rd; char *ptr; int n; int a, c, opcode; char id[NCPS]; listaddr = dot->s_value; listmode = skip ? NLIST : SLIST; /* if skiping then no list */ lsp = NULL; c = getnb(); do{ if(c=='\0' || c==';' || c=='\n' || c=='\f') /* + ^L gpv */ break; if( c == '-' ){ /* --- gpv 3april'86 */ mkobj = 0; break; } if( c == '+') { mkobj = nflag; break; } if( c == '!' ) c = getnb(); if(!alpha(c)) { if( !skip ) err('L'); break; } getid(c, id); if(( c = getnb()) == ':' ) { if( skip ) break; sp=install(id, 'd'); if(pass==0) { if(sp->s_type!=S_UND && (sp->s_flag&SF_ASG)==0) sp->s_flag |= SF_MDF; sp->s_type = S_ABS; sp->s_value = dot->s_value; } else { if((sp->s_flag&SF_MDF)!=0) err('L'); if(sp->s_type!=S_ABS || sp->s_value!=dot->s_value) err('L'); } listmode = ALIST; continue; } else putback(c); if((sp=lookup(id)) == NULL){ if( !skip ){ lsp = install( id, '=' ); c = getnb(); getid( c , id ); if((sp = lookup(id)) == NULL){ err('O'); break; } } else return; } else if (skip &&(sp->s_type != S_ENDIF)) return; else if((skip || inif)&&(sp->s_type == S_ENDIF)) { skip = 0; if(!(--inif)) inif=0; listmode = NLIST; return; } listmode = CLIST; if( lsp != NULL ){ switch( sp->s_type){ case S_EQU: case S_SET: if( lsp->s_type != S_UND && ( lsp->s_flag&SF_ASG) == 0) err('L'); lsp->s_type = S_ABS; lsp->s_flag |= SF_ASG; lsp->s_value = listaddr = expr(); listmode = ALIST; lsp = NULL; break; case S_MACRO: lsp = NULL; err('M'); break; } } if( lsp != NULL ){ if(pass==0) { if(lsp->s_type!=S_UND && (lsp->s_flag&SF_ASG)==0) lsp->s_flag |= SF_MDF; lsp->s_type = S_ABS; lsp->s_value = dot->s_value; } else { if((lsp->s_flag&SF_MDF)!=0) err('L'); if(lsp->s_type!=S_ABS || lsp->s_value!=dot->s_value) err('p'); } lsp = NULL; } listmode = CLIST; opcode = sp->s_value; switch(sp->s_type) { case S_EQU: case S_SET: case S_MACRO: break; case S_IF: inif += 1; skip = (expr()==0); listmode = NLIST; return; case S_NAME: n = TITLE_LN; c=getnb(); ptr = title; while((*ptr++ = getraw())!=c && --n>0); *(--ptr) = '\0'; return; case S_ORG: listaddr = dot->s_value = expr(); break; case S_ENTRY: entaddr = expr(); return; case S_BYTE: do { if ( (c=getnb())=='\'') ascii(c); else{ putback( c ); a = expr(); byte(a); codeb(a); } } while((c=getnb()) == ','); putback(c); break; case S_WORD: do { codew(expr()); } while((c=getnb()) == ','); putback(c); break; case S_BLKB: a = expr(); /* while(a--) codeb(0); */ dot->s_value += a; listmode = ALIST; break; case S_OP1: codeb(opcode); break; case S_OP2: a = expr(); byte(a); codeb(opcode); codeb(a); break; case S_OP3: rd = getreg(S_REG); comma(); a = expr(); byte(a); code3(opcode, rd); codeb(a); break; case S_OP4: rd = getreg(S_REG); comma(); rs = getreg(S_REG); codeb(opcode | rd<<3 | rs); break; case S_OP5: if((rd=getreg(S_REG))!=B && rd!=D) err('a'); code4(opcode, rd); break; case S_OP6: if((rd=getreg(S_REG)) == PSW){ err('R'); } code4(opcode, rd); break; case S_OP7: if((rd=getreg(S_REG)) == SP) err('a'); code4(opcode, rd); break; case S_OP8: a = expr(); if(a<0 || a>7) err('t'); code3(opcode, a&07); break; case S_OP9: rs = getreg(S_REG); if(opcode==INR || opcode==DCR) code3(opcode, rs); else codeb(opcode | rs); break; case S_OP10: if((rd=getreg(S_REG)) == PSW) err('a'); comma(); a = expr(); code4(opcode, rd); codew(a); break; case S_OP11: a = expr(); codeb(opcode); codew(a); break; default: err('C'); } /* end of case statement */ } while( ( c = getnb()) != '\0' && c != ';' ); } /* * Process the body of .ascii * and .asciz pseudo ops. * The z flag is true for a * .asciz */ ascii(delim) char delim; { register int c; while((c=getmap())!='\0' && c!=delim) codeb(c); if(c == '\0') err('S'); } /* * Get a register. * Type is either S_REG or S_REGP. */ getreg(type) { register struct sym *sp; register int c; char id[NCPS]; if(!alpha(c=getnb())) { err('R'); putback(c); return(0); } getid(c, id); if((sp=lookupreg(id))==NULL || type != sp->s_type) { err('R'); return(0); } return(sp->s_value); } /* * Insure that the value of * an expression is a legal * byte value. * Error if not. */ byte(b) { if((b&0200)!=0) b |= ~0377; if(b>127 || b<-128) err('R'); } /* * Check for `,'. */ comma() { if(getnb() != ',') err('a'); } /* * Build instructions of the * general form xxrrrxxx. */ code3(x, r) { codeb(x | r<<3); } /* * Build instructions of the * general form xxrrxxxx. */ code4(x, r) { codeb(x | (r&6)<<3); } SHAR_EOF if test 5430 -ne "`wc -c < 'as81.c'`" then echo shar: "error transmitting 'as81.c'" '(should have been 5430 characters)' fi fi echo shar: "extracting 'as82.c'" '(2878 characters)' if test -f 'as82.c' then echo shar: "will not over-write existing file 'as82.c'" else cat << \SHAR_EOF > 'as82.c' /* * as82.c * Expressions. */ #include <stdio.h> #include "asm.h" #ifndef lint static char *sccsid="@(#)as82.c 1.2"; #endif /* * Read an expression. * Return its value. * All expressions are evaluated * left to right; parentheses * may be used to alter the order * of evaluation. */ int expr() { register int c; int l, r; if(!term(&l)) return(0); while(validop(c=getopr())) { if(!term(&r)) { err('e'); return(l); } switch(c) { case '+': l += r; break; case '-': l -= r; break; case '*': l *= r; break; case '/': l /= r; break; case '&': l &= r; break; case '|': l |= r; break; case '^': l ^= r; break; case '%': l %= r; break; case '<': l <<= r; break; case '>': l >>= r; break; } } putback(c); return(l); } /* * Check for valid arithmetic * operators. */ validop(c) { return( instr( c,"+-*/%&|<>^") >= 0); } /* * Get a term. * Store its value in the * indicated place. * Return true if a term is * found. * If no term is found no * characters are read and * false is returned. */ int term(vp) int *vp; { register struct sym *sp; register int c; char id[NCPS]; /* * Number. */ if(digit(c=getnb())) { *vp = getnum(c); return(1); /* * Id. */ } else if(alpha(c)) { getid(c, id); if( strcmp(id,"not")== 0){ /* if the id is 'not' */ term(vp); *vp = ~*vp; } else { sp = install(id, 'e'); if(sp == NULL ) err( 'U'); else if(sp->s_type == S_UND) err('u'); *vp = sp->s_value; } return(1); /* * Unary ops. */ } else if(c=='-') { if(!term(vp)) { err('e'); return(0); } *vp = -*vp; /* * Parentheses. */ } else if(c == '(') { *vp = expr(); if(getnb() != ')') err('('); return(1); /* * Character constant. */ } else if(c == '\'') { *vp = getmap(); if(getnb() != '\'') { putback(c); *vp = *vp+(getmap()<<8); if(getnb() != '\'') err('\''); } return(1); /* * The current value of DOT */ } else if ( c == CDOT ){ *vp = dot->s_value; return(1); /* * None. */ } else { putback(c); return(0); } } /* * getopr() * * Get a valid operator. * * Finds non-unix type operators and returns them as valid * Unix operators. * */ getopr() { char ch; char id[ NCPS ]; int index; if( validop(ch=getnb()) ) return(ch); if( alpha(ch)) getid( ch, id); else return(ch); if( strcmp( id , "and") == 0) return('&'); else if( strcmp( id, "or") == 0) return('|'); else if( strcmp( id, "xor") == 0) return('^'); else if( strcmp( id, "mod") == 0) return('%'); else if( strcmp( id, "shr") == 0) return('>'); else if( strcmp( id, "shl") == 0) return('<'); else for( index = strlen(id); index==1 ;index--) putback( id[ index] ); return( id[ 0 ]); } SHAR_EOF if test 2878 -ne "`wc -c < 'as82.c'`" then echo shar: "error transmitting 'as82.c'" '(should have been 2878 characters)' fi fi echo shar: "extracting 'as83.c'" '(2594 characters)' if test -f 'as83.c' then echo shar: "will not over-write existing file 'as83.c'" else cat << \SHAR_EOF > 'as83.c' /* * Lex. */ #include <stdio.h> #include "asm.h" #ifndef lint static char *sccsid="@(#)as83.c 1.2"; #endif /* * Get the next non white * character. */ int _getnb() { register int c; while(space(c=getraw())) ; return(c); } /* * Get next character from * the input. * Apply string mappings. */ getmap() { register int n, c, v; if((c=getraw()) == '\\') switch(c = getraw()) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'b': c = '\b'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': v = n = 0; while(++n<=3 && c>='0' && c<='7') { v = 8*v + c - '0'; c = getraw(); } putback(c); c = v; break; default: putback(c); c = '\\'; } return(c); } /* * Read in an indentifier. * Store it (padded with nulls) into the * supplied buffer. */ getid(c, id) register int c; char *id; { register char *p, *end; p = id; end = &id[NCPS]; while(alpha(c) || digit(c) || c== '$') { if(p < end){ if (upper(c)) c |= ' '; if (c != '$') *p++ = c; } c = getraw(); } *p = '\0'; putback(c); } /* * instr( c,str) * * returns the index to locate c in str if c is in str. * if c is not in str then returns -1. */ int instr( c, str ) char c; char *str; { register char *lp; lp = str; while( *lp != '\0' ) if( *lp++ == c ) return( lp-str-1 ); return( -1 ); } /* * get a number; * */ static char *hexstr = "0123456789ABCDEF"; int getnum(c) char c; { static char *radix = "BDHOQ"; static int radv[]={ 10,2,10,16,8,8 }; char numbstr[ 16 ]; char *np; np = numbstr; while( instr( ucase( c ), hexstr) >= 0 ){ *np++=ucase( c ); c = getraw(); } *np-- = '\0'; if( instr( ucase( c ), radix ) < 0 ){ putback(c ); /* if terminal not right */ c = *np; /* then the previous is */ if( instr( ucase( c ), radix ) >= 0 ) *np = '\0'; } /* * The following code uses the index into the radix array to * calculate the correct index into radix value table and * use the value found to determine the correct conversion * routine. * * Think carefully before changing the following code. * */ return( scnnumb( numbstr, radv[ 1 + instr( ucase( c ), radix )])); } int scnnumb( str ,radix ) char *str; int radix; { int v ,d; v = 0; while( *str ) if( (d=instr( *str++, hexstr)) >= 0 && d < radix ) v = v*radix + d; else return( err( 'N' ), 0 ); return( v ); } SHAR_EOF if test 2594 -ne "`wc -c < 'as83.c'`" then echo shar: "error transmitting 'as83.c'" '(should have been 2594 characters)' fi fi echo shar: "extracting 'as85.c'" '(8133 characters)' if test -f 'as85.c' then echo shar: "will not over-write existing file 'as85.c'" else cat << \SHAR_EOF > 'as85.c' /* * as85.c * Tables. * Added 'rim' and 'sim' to keyword list. 3Apr'86 -- gpv */ #include <stdio.h> #include "asm.h" /* * Assorted variables. */ #ifndef lint static char *sccsid="@(#)as85.c 1.2"; #endif int listmode; /* Listing control */ int listaddr; /* Listing control */ int entaddr; /* Entry address */ FILE *src; /* Source */ FILE *lst; /* Listing */ FILE *obj; /* Object */ int lflag; /* -l flag */ int nflag; /* -n flag */ int sflag; /* -s flag */ int pass; /* Which pass? */ int skip; /* skipping code */ int inif; /* in an if block */ int lineno; /* Line number */ char *sptr; /* Source pointer */ char sbuf[SRCMAX]; /* Source buffer */ char *cptr; /* Listing code pointer */ char cbuf[CLMAX]; /* Listing code buffer */ char *eptr; /* Error pointer */ char ebuf[ERRMAX]; /* Error buffer */ int cadr; /* Object address */ int crec; /* Object index */ char crbf[CBMAX]; /* Object buffer */ int errcnt; /* error count */ int page; /* current page number */ int pline; /* lines on the current page */ char title[TITLE_LN+1]; /* program listing title */ char chartype[128] = { /* character class */ /* | 00 nul| 01 soh| 02 stx| 03 etx| 04 eot| 05 enq| 06 ack| 07 bel| */ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, /* | 08 bs | 09 ht | 0a nl | 0b vt | 0c np | 0d cr | 0e so | 0f si | */ UNKNOWN, SPACE, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, /* | 10 dle| 11 dc1| 12 dc2| 13 dc3| 14 dc4| 15 nak| 16 syn| 17 etb| */ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, /* | 18 can| 19 em | 1a sub| 1b esc| 1c fs | 1d gs | 1e rs | 1f us | */ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, /* | 20 sp | 21 ! | 22 " | 23 # | 24 $ | 25 % | 26 & | 27 ' | */ SPACE, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, /* | 28 ( | 29 ) | 2a * | 2b + | 2c , | 2d - | 2e . | 2f / | */ UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, /* | 30 0 | 31 1 | 32 2 | 33 3 | 34 4 | 35 5 | 36 6 | 37 7 | */ DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, /* | 38 8 | 39 9 | 3a : | 3b ; | 3c < | 3d = | 3e > | 3f ? | */ DIGIT, DIGIT, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, OTHER, /* | 40 @ | 41 A | 42 B | 43 C | 44 D | 45 E | 46 F | 47 G | */ OTHER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, /* | 48 H | 49 I | 4a J | 4b K | 4c L | 4d M | 4e N | 4f O | */ UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, /* | 50 P | 51 Q | 52 R | 53 S | 54 T | 55 U | 56 V | 57 W | */ UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, UPPER, /* | 58 X | 59 Y | 5a Z | 5b [ | 5c \ | 5d ] | 5e ^ | 5f _ | */ UPPER, UPPER, UPPER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, /* | 60 ` | 61 a | 62 b | 63 c | 64 d | 65 e | 66 f | 67 g | */ UNKNOWN, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, /* | 68 h | 69 i | 6a j | 6b k | 6c l | 6d m | 6e n | 6f o | */ LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, /* | 70 p | 71 q | 72 r | 73 s | 74 t | 75 u | 76 v | 77 w | */ LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, LOWER, /* | 78 x | 79 y | 7a z | 7b { | 7c | | 7d } | 7e ~ | 7f del| */ LOWER, LOWER, LOWER, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, }; struct sym *hashtbl[HASH]; /* symbol table hashbuckets */ /* * User symbol table. * The first item must be '$'. */ struct sym ust[USERMAX] = {"$", NULL,NULL, S_ABS, SF_ASG, 0}; /* * Opcode table. * Also contains pseudo operations. */ struct sym pst[] = { "aci", NULL, NULL, S_OP2, 0, 0316, NULL, "adc", NULL, NULL, S_OP9, 0, 0210, NULL, "add", NULL, NULL, S_OP9, 0, 0200, NULL, "adi", NULL, NULL, S_OP2, 0, 0306, NULL, "ana", NULL, NULL, S_OP9, 0, 0240, NULL, "ani", NULL, NULL, S_OP2, 0, 0346, NULL, "call", NULL, NULL, S_OP11, 0, 0315, NULL, "cc", NULL, NULL, S_OP11, 0, 0334, NULL, "cm", NULL, NULL, S_OP11, 0, 0374, NULL, "cma", NULL, NULL, S_OP1, 0, 0057, NULL, "cmc", NULL, NULL, S_OP1, 0, 0077, NULL, "cmp", NULL, NULL, S_OP9, 0, 0270, NULL, "cnc", NULL, NULL, S_OP11, 0, 0324, NULL, "cnz", NULL, NULL, S_OP11, 0, 0304, NULL, "cp", NULL, NULL, S_OP11, 0, 0364, NULL, "cpe", NULL, NULL, S_OP11, 0, 0354, NULL, "cpi", NULL, NULL, S_OP2, 0, 0376, NULL, "cpo", NULL, NULL, S_OP11, 0, 0344, NULL, "cz", NULL, NULL, S_OP11, 0, 0314, NULL, "daa", NULL, NULL, S_OP1, 0, 0047, NULL, "dad", NULL, NULL, S_OP6, 0, 0011, NULL, "db", NULL, NULL, S_BYTE, 0, 0, NULL, "dcr", NULL, NULL, S_OP9, 0, 0005, NULL, "dcx", NULL, NULL, S_OP6, 0, 0013, NULL, "di", NULL, NULL, S_OP1, 0, 0363, NULL, "ds", NULL, NULL, S_BLKB, 0, 0, NULL, "dw", NULL, NULL, S_WORD, 0, 0, NULL, "ei", NULL, NULL, S_OP1, 0, 0373, NULL, "end", NULL, NULL, S_ENTRY, 0, 0, NULL, "endif", NULL, NULL, S_ENDIF, 0, 0, NULL, "endm", NULL, NULL, S_ENDM, 0, 0, NULL, "equ", NULL, NULL, S_EQU, 0, 0, NULL, "hlt", NULL, NULL, S_OP1, 0, 0166, NULL, "if", NULL, NULL, S_IF, 0, 0, NULL, "in", NULL, NULL, S_OP2, 0, 0333, NULL, "inr", NULL, NULL, S_OP9, 0, 0004, NULL, "inx", NULL, NULL, S_OP6, 0, 0003, NULL, "jc", NULL, NULL, S_OP11, 0, 0332, NULL, "jm", NULL, NULL, S_OP11, 0, 0372, NULL, "jmp", NULL, NULL, S_OP11, 0, 0303, NULL, "jnc", NULL, NULL, S_OP11, 0, 0322, NULL, "jnz", NULL, NULL, S_OP11, 0, 0302, NULL, "jp", NULL, NULL, S_OP11, 0, 0362, NULL, "jpe", NULL, NULL, S_OP11, 0, 0352, NULL, "jpo", NULL, NULL, S_OP11, 0, 0342, NULL, "jz", NULL, NULL, S_OP11, 0, 0312, NULL, "lda", NULL, NULL, S_OP11, 0, 0072, NULL, "ldax", NULL, NULL, S_OP5, 0, 0012, NULL, "lhld", NULL, NULL, S_OP11, 0, 0052, NULL, "lxi", NULL, NULL, S_OP10, 0, 0001, NULL, "macro", NULL, NULL, S_MACRO, 0, 0, NULL, "mov", NULL, NULL, S_OP4, 0, 0100, NULL, "mvi", NULL, NULL, S_OP3, 0, 0006, NULL, "nop", NULL, NULL, S_OP1, 0, 0000, NULL, "ora", NULL, NULL, S_OP9, 0, 0260, NULL, "org", NULL, NULL, S_ORG, 0, 0, NULL, "ori", NULL, NULL, S_OP2, 0, 0366, NULL, "out", NULL, NULL, S_OP2, 0, 0323, NULL, "pchl", NULL, NULL, S_OP1, 0, 0351, NULL, "pop", NULL, NULL, S_OP7, 0, 0301, NULL, "push", NULL, NULL, S_OP7, 0, 0305, NULL, "ral", NULL, NULL, S_OP1, 0, 0027, NULL, "rar", NULL, NULL, S_OP1, 0, 0037, NULL, "rc", NULL, NULL, S_OP1, 0, 0330, NULL, "ret", NULL, NULL, S_OP1, 0, 0311, NULL, "rim", NULL, NULL, S_OP1, 0, 0040, NULL, "rlc", NULL, NULL, S_OP1, 0, 0007, NULL, "rm", NULL, NULL, S_OP1, 0, 0370, NULL, "rnc", NULL, NULL, S_OP1, 0, 0320, NULL, "rnz", NULL, NULL, S_OP1, 0, 0300, NULL, "rp", NULL, NULL, S_OP1, 0, 0360, NULL, "rpe", NULL, NULL, S_OP1, 0, 0350, NULL, "rpo", NULL, NULL, S_OP1, 0, 0340, NULL, "rrc", NULL, NULL, S_OP1, 0, 0017, NULL, "rst", NULL, NULL, S_OP8, 0, 0307, NULL, "rz", NULL, NULL, S_OP1, 0, 0310, NULL, "sbb", NULL, NULL, S_OP9, 0, 0230, NULL, "sbi", NULL, NULL, S_OP2, 0, 0336, NULL, "set", NULL, NULL, S_SET, 0, 0, NULL, "shld", NULL, NULL, S_OP11, 0, 0042, NULL, "sim", NULL, NULL, S_OP1, 0, 0060, NULL, "sphl", NULL, NULL, S_OP1, 0, 0371, NULL, "sta", NULL, NULL, S_OP11, 0, 0062, NULL, "stax", NULL, NULL, S_OP5, 0, 0002, NULL, "stc", NULL, NULL, S_OP1, 0, 0067, NULL, "sub", NULL, NULL, S_OP9, 0, 0220, NULL, "sui", NULL, NULL, S_OP2, 0, 0326, NULL, "title", NULL, NULL, S_NAME, 0, 0, NULL, "xchg", NULL, NULL, S_OP1, 0, 0353, NULL, "xra", NULL, NULL, S_OP9, 0, 0250, NULL, "xri", NULL, NULL, S_OP2, 0, 0356, NULL, "xthl", NULL, NULL, S_OP1, 0, 0343, NULL, }; /* * Register symbol table */ struct sym rst[] = { "a", NULL, NULL, S_REG, 0, 7, NULL, "b", NULL, NULL, S_REG, 0, 0, NULL, "c", NULL, NULL, S_REG, 0, 1, NULL, "d", NULL, NULL, S_REG, 0, 2, NULL, "e", NULL, NULL, S_REG, 0, 3, NULL, "h", NULL, NULL, S_REG, 0, 4, NULL, "l", NULL, NULL, S_REG, 0, 5, NULL, "m", NULL, NULL, S_REG, 0, 6, NULL, "psw", NULL, NULL, S_REG, 0, PSW, NULL, "sp", NULL, NULL, S_REG, 0, SP, NULL }; /* * Size of tables. * Must be here! */ int pstsiz = (sizeof(pst)/sizeof(pst[0])); int rstsiz = (sizeof(rst)/sizeof(rst[0])); SHAR_EOF if test 8133 -ne "`wc -c < 'as85.c'`" then echo shar: "error transmitting 'as85.c'" '(should have been 8133 characters)' fi fi echo shar: "extracting 'asm.c'" '(11527 characters)' if test -f 'asm.c' then echo shar: "will not over-write existing file 'asm.c'" else cat << \SHAR_EOF > 'asm.c' /* * asm.c * Mainline. * * Revisions: * * ------------------------------------------------------------------------ * Simple changes by Gordon P. Vickers @ Sigfac on 3 April '86: * edited as83.c so '@' will be allowed in label, variable fields. * edited as85.c, add 'rim' and 'sim' to keyword list. * edited as81.c, asm.c: add variable 'mkobj' to allow source file * contents to turn on/off hex file generation. * NOTE: for specific changes use the search key: gpv * ----------------------------------------------------------------------- * */ #include <stdio.h> #include "asm.h" #ifndef lint static char *sccsid="@(#)asmain.c 1.4"; #endif char *malloc(); /* * This is the mainline. * It scans the command line, * collects up a source file, * sets option flags and calls * the assembler proper. */ int mkobj = 1; /* hex file generation switch. - gpv */ static int cflag = 0; /* cross reference on flag */ main(argc, argv) char *argv[]; { register int i, c; register char *p; char *file; file = NULL; for(i=1; i<argc; ++i) { p = argv[i]; if(*p++ == '-') { while(c = *p++) switch(c) { case 'l': case 'L': ++lflag; break; case 'c': case 'C': ++lflag; ++cflag; break; case 'n': case 'N': ++nflag; break; case 's': case 'S': ++lflag; ++sflag; break; default: usage(); } } else { file = argv[i]; if(file == NULL) usage(); assemble(file); } } } /* * Assemble a file. */ assemble(file) char *file; { char fn[40]; int index; strncpy(title,file,20); for ( index = 0 ; index < HASH ; index ++) hashtbl[ index ] = NULL; name(fn, file, "asm", 0); if((src=fopen(fn, "r")) == NULL) { fprintf(stderr, "%s: cannot open\n", fn); exit(1); } if(lflag) { name(fn, file, "lst", 1); if((lst=fopen(fn, "w")) == NULL) { fprintf(stderr, "%s: cannot create\n", fn); exit(1); } } if(mkobj) { /* mkobj - 3April'86 -- gpv */ name(fn, file, "hex", 1); if((obj=fopen(fn, "w")) == NULL) { fprintf(stderr, "%s: cannot create\n", fn); exit(1); } } page = 1; for(pass=0; pass<2; ++pass) { skip = 0; /* not currently skipping*/ rewind(src); errcnt = 0; lineno = 0; dot->s_type = S_ABS; dot->s_flag = SF_ASG; dot->s_value = 0; if(pass && lflag ) top(0); while(fgets(sbuf, SRCMAX , src) != NULL) { ++lineno; sptr = sbuf; cptr = cbuf; eptr = ebuf; asmline(); if(pass) { outerrors(); if(lflag) outlisting(); } } } if(errcnt) printf(" Total errors = %5d\n",errcnt); if(lflag){ if(errcnt){ fprintf(lst,"\n Total number of errors = %5d \n",errcnt) ; } table(); fclose(lst); } if(mkobj){ /* mkobj 3 April'86 -- gpv */ cflush(1); fclose(obj); } printf(" Total bytes assembled = %04X\n", dot->s_value); fclose(src); } /* * If the user screws up, put out * a usage message. * Then quit. * Not much sense staying around. */ usage() { fprintf(stderr, "Usage:%4s [-ln] file file ...\n",TASK); fprintf(stderr, "where: \n"); fprintf(stderr, " l = make a listing \n"); fprintf(stderr, " and n = don't make an object file\n"); exit(1); } /* * Build RSX file names. * The mode argument is either 0 * which means default, or 1 which * means replace with. */ name(fn, file, type, mode) char *fn, *file, *type; { register char *p1, *p2; register int c; p1 = fn; p2 = file; while((c = *p2++) && c!='.') *p1++ = c; if(mode == 0) { if(c == '.') { do { *p1++ = c; } while(c = *p2++); } else { *p1++ = '.'; p2 = type; while(c = *p2++) *p1++ = c; } } else { *p1++ = '.'; p2 = type; while(c = *p2++) *p1++ = c; } *p1 = '\0'; } /* * Output code byte. * Save it in the per line * buffer for outlisting. * Update dot. */ codeb(b) int b; { b &= 0377; if(cptr < &cbuf[CLMAX]) *cptr++ = b; if(pass && mkobj) { /* mkobj 3 April'86 -- gpv */ if(crec>=CBMAX || cadr+crec!=dot->s_value) { cflush(0); cadr = dot->s_value; } crbf[crec++] = b; } ++dot->s_value; } /* * Output a word. * Low then high. */ codew(w) { if(BSWAP)codeb(w>>8); codeb(w); if(!BSWAP)codeb(w>>8); } /* * Signal error. * Add it to the error buffer * if not already there. */ err(c) { register char *p; errcnt+=1; p = ebuf; if(eptr == &ebuf[ERRMAX-1]) c ='*'; while(p < eptr) if(*p++ == c) return; *p++ = c; if ( p> &ebuf[ERRMAX]) --p; eptr = p; } /* * Format a line for the * listing. * More work than you would * think. * Only called if -l. */ outlisting() { register int nbytes; register char *cp; int w1, w2, w3, w4; if(listmode == NLIST) return; for(cp = eptr; cp < &ebuf[ERRMAX-1]; *cp++ = ' '); *cp='\0'; if(!(--pline )) top(1); if(listmode == SLIST) fprintf(lst, "%.6s ", ebuf); else fprintf(lst, "%.6s %04X ", ebuf, listaddr); if(listmode == ALIST) fprintf(lst, "%9s%4d %s", "", lineno, sbuf); else { nbytes = cptr-cbuf; w1 = cbuf[0]&0377; w2 = cbuf[1]&0377; w3 = cbuf[2]&0377; w4 = cbuf[3]&0377; switch(nbytes) { case 0: fprintf(lst, "%9s", ""); break; case 1: fprintf(lst, "%02X%7s", w1, ""); break; case 2: fprintf(lst, "%02X%02X%5s", w1, w2, ""); break; case 3: fprintf(lst, "%02X%02X%02X%3s", w1, w2, w3,""); break; default: fprintf(lst, "%02X%02X%02X%02X%1s", w1, w2, w3,w4,""); } fprintf(lst, "%4d\t%s", lineno, sbuf); cp = &cbuf[4]; while((nbytes -= 4) > 0) { if( --pline < 0 ) top(1); listaddr += 4; fprintf(lst, "%5s%04X ", "",listaddr ); switch(nbytes) { case 0: break; case 1: w1 = cp[0]&0377; fprintf(lst, "%02X\n", w1); break; case 2: w1 = cp[0]&0377; w2 = cp[1]&0377; fprintf(lst, "%02X%02X\n", w1, w2); break; case 3: w1 = cp[0]&0377; w2 = cp[1]&0377; w3 = cp[2]&0377; fprintf(lst, "%02X%02X%02X\n", w1, w2, w3); break; default: w1 = cp[0]&0377; w2 = cp[1]&0377; w3 = cp[2]&0377; w4 = cp[3]&0377; fprintf(lst, "%02X%02X%02X%02X\n", w1, w2, w3,w4); } cp += 4; } } } /* * Write errors to the tty. */ outerrors() { if( lflag ) return; if( eptr > ebuf ){ *eptr='\0'; printf("%s\t%04d\t%s", ebuf, lineno, sbuf); } } /* * Flush the binary code * buffer. */ cflush(lf) int lf; { int chksum; /* checksum for hex file format */ register int i; if(crec == 0) return; putc(':', obj); ohb(obj, crec & 0xff); ohb(obj, (cadr >> 8) & 0xff); ohb(obj, cadr & 0xff); putc('0', obj); putc('0', obj); chksum = 0; chksum += crec; chksum += (( cadr >> 8)& 0xFF); chksum += ( cadr & 0xFF); for(i=0; i<crec; ++i){ ohb(obj, crbf[i] & 0xff); chksum += crbf[ i ]&0xFF; } ohb(obj, (0-(chksum & 0xff)) & 0xff); putc('\n', obj); crec = 0; if(lf) fprintf(obj,":00000000\n"); } ohb (filep, byte) FILE *filep; int byte; /* ** More efficient than using the general purpose fprintf */ { static char hex[] = "0123456789ABCDEF"; putc ( hex[(byte >> 4) & 0xf], filep ); putc ( hex[byte & 0xf], filep ); } /* * Print out the user symbol table */ table() { register struct sym *mine ; register struct hu *howu; int line,indx,count; count =line = 0; page = 1; fprintf(lst,"\f\n%-40s Symbol table dump \t\t Page %3d\n\n\n", title,page++) ; for( indx = 0 ; indx < HASH ; indx++){ for(mine = hashtbl[ indx ]; mine != NULL; mine = mine->right ){ if( line >= mxline ){ fprintf(lst, "\f\n Symbol table dump page %3d\n\n\n" ,page++); line = 0; } fprintf(lst,"%10s = %04X ",mine->s_name,mine->s_value); if( cflag ){ for( howu = mine->howused; howu != NULL ; howu = howu->next ){ if( count >= 10 ){ fprintf(lst,"\n "); line++; count = 0; } fprintf(lst,"%6d %c :", howu->line, howu->how ); count++; } count = 0; line++; fprintf(lst,"\n"); } else{ if( count >= 4 ){ line++; count = 0; fprintf(lst,"\n"); } count++; } } } fprintf(lst,"\f\n"); fflush(lst); } /* * * Top - Print the label at the top of the page * */ top(mode) int mode; { if(mode)putc('\f',lst); pline = mxline; fprintf(lst,"\n %-40s KSE cross assembler for the %-5s",title,MICRO); fprintf(lst," page %3d",page++); fprintf(lst," \n\n\n"); } int hash( id ) char *id; { register unsigned u; register char *p; u = 0; p = id; while (*p != '\0') u = (u << 1) + *p++; return (u % HASH); } struct sym * lkup( id , howu ) char *id; char howu; { struct sym *np; struct hu *usage; for( np = hashtbl[hash(id)]; np != NULL; np = np->right ){ if( strcmp( id, np->s_name ) == 0){ if( cflag ){ for( usage = np->howused; usage->line != lineno && usage->next != NULL; usage = usage->next ) ; if( usage->line != lineno ){ usage->next =(struct hu *) malloc( sizeof( *usage)); if( usage->next != NULL){ usage->next->line = lineno; usage->next->how =howu; usage->next->next = NULL; } } } return( np ); } } return(NULL ); } struct sym * install( id , howu ) char *id; char howu; { struct sym *np,*lp; struct sym *lkup(); int hashval; if( (np = lkup( id , howu ) ) == NULL ) { np= ( struct sym *)malloc( sizeof( *np )); if(np == NULL ){ fprintf(stderr,"in line %d ",lineno); fprintf(stderr,"Symbol table overflow\n"); return( NULL ); } np->right = NULL; np->left = NULL; np->s_type= 0; np->s_flag= 0; np->s_value = 0; if( cflag ){ np->howused = (struct hu *)malloc( sizeof( *np->howused)); if( np->howused != NULL ){ np->howused->how = howu; np->howused->line = lineno; np->howused->next = NULL; } } strcpy(np->s_name,id); hashval = hash( id ); if( hashtbl[ hashval ] == NULL ){ hashtbl[ hashval ] = np; } else if( strcmp( id , hashtbl[hashval]->s_name ) > 0 ){ hashtbl[ hashval ]->left = np; np->right = hashtbl[ hashval ]; hashtbl[ hashval] = np; } else for( lp = hashtbl[hashval];lp != NULL;lp = lp->right) { if( lp->right == NULL ){ lp->right = np; np->left = lp; break; } else if ( strcmp( id, lp->right->s_name ) < 0){ np->right = lp->right; lp->right->left = np; lp->right = np; np->left = lp; break; } } } return( np ); } /* * Lookup id in pst. */ struct sym * lookup(id) char *id; { register int i, lo, hi, mid; register char *p, *name; register struct sym *s; for (lo = 0, hi = pstsiz - 1; lo <= hi; ) { mid = (lo + hi) / 2; p = id; name = pst[mid].s_name; while (*p != '\0' && *p == *name) ++p, ++name; if ((i = *p - *name) == 0) break; else if (i < 0) hi = mid - 1; else lo = mid + 1; } if (lo > hi) return( NULL); else return( &pst[mid] ); } /* * Lookup id in rst. */ struct sym * lookupreg(id) char *id; { register int i, lo, hi, mid; register char *p, *name; for (lo = 0, hi = rstsiz - 1; lo <= hi; ) { mid = (lo + hi) / 2; p = id; name = rst[mid].s_name; while (*p != '\0' && *p == *name) ++p, ++name; if ((i = *p - *name) == 0) break; else if (i < 0) hi = mid - 1; else lo = mid + 1; } if (lo > hi) return( NULL); else return( &rst[mid] ); } SHAR_EOF if test 11527 -ne "`wc -c < 'asm.c'`" then echo shar: "error transmitting 'asm.c'" '(should have been 11527 characters)' fi fi echo shar: "extracting 'asm.h'" '(5187 characters)' if test -f 'asm.h' then echo shar: "will not over-write existing file 'asm.h'" else cat << \SHAR_EOF > 'asm.h' /* * @(#)asm.h 1.3 * Header. * * General assembler header. With this structure you * can define the majority of the simple assembler * dependent variables. * * David A Klotzbach * * Sizes of tables. */ #define NCPS 16 /* Characters per symbol */ #define CLMAX 256 /* Code bytes, line */ #define CBMAX 16 /* Code bytes, object */ #define USERMAX 2 /* User names */ #define SRCMAX 128 /* Source line length */ #define ERRMAX 5 /* Maximum errors per line +1 */ #define FALSE 0 /* not true */ #define TRUE 1 /* You should be able to guess */ #define mxline 9999 /* maximum lines per page*/ #define dot (&ust[0]) /* Location counter */ #define CDOT '$' /* Character that means current PC */ #define BSWAP 0 /* 1 = High first; 0 = Low first */ #define MICRO "8080" #define TASK "ASM80" /* The task that is to be run */ #define HASH 1009 /* * Listing control modes. * Go in `listmode'. */ #define NLIST 0 /* No list */ #define SLIST 1 /* Source only list */ #define ALIST 2 /* Just address */ #define CLIST 3 /* Address and code */ /* * Symbol table structure. * Used in both the user symbol table and * the opcode table. */ struct hu{ struct hu *next; /* Next usage */ int line; /* Line used */ char how; /* How it was used */ }; #define U_DEFINE 'd' /* Defined */ #define U_EXPR 'e' /* used in expres */ #define U_EQU '=' /* EQU or SET */ struct sym { char s_name[NCPS]; /* Name */ struct sym *left; /* left member */ struct sym *right; /* right member */ char s_type; /* Type */ char s_flag; /* Some flags */ int s_value; /* Value */ struct hu *howused; /* First entry in */ }; struct sym *hashtbl[ ]; /* Hash buckets for symbol table */ #define B 0 #define C 1 #define D 2 #define E 3 #define H 4 #define L 5 #define M 6 #define A 7 #define PSW 6 #define SP 7 #define INR 4 #define DCR 5 /* * Types. */ #define S_UND 0 /* Undefined */ #define S_ABS 1 /* Absolute */ #define S_REG 2 /* Register */ #define S_REGP 3 /* Register pair */ #define S_ENTRY 4 /* .entry */ #define S_BYTE 5 /* .byte */ #define S_WORD 6 /* .word */ #define S_ASCII 7 /* .ascii */ #define S_ASCIZ 8 /* .asciz */ #define S_BLKB 9 /* .blkb */ #define S_OP1 10 /* Opcode */ #define S_OP2 11 /* Accumulator and Memory */ #define S_OP3 12 /* Index Register and stack */ #define S_OP4 13 /* Branch */ #define S_OP5 14 /* Jump */ #define S_OP6 15 /* Condition codes */ #define S_OP7 16 /* limitted to extnd and indexed */ #define S_OP8 17 /* limitted to direct,extnd and indx */ #define S_OP9 18 /* */ #define S_OP10 19 /* */ #define S_OP11 20 /* */ #define S_EQU 21 /* */ #define S_SET 22 /* */ #define S_NAME 23 /* Name the program listing */ #define S_ORG 24 /* Program section origin statement */ #define S_IF 100 /* IF directive */ #define S_ENDIF 102 /* ENDIF directive */ #define S_MACRO 200 /* Define a macro */ #define S_ENDM 202 /* Define macro end */ /* * Flags. */ #define SF_MDF 01 /* Multiply defined */ #define SF_ASG 02 /* Defined by assignment */ #define SF_MAC 04 /* is a MACRO definition */ /* * Variables. */ #define TITLE_LN 40 /* Length of the title */ extern struct sym pst[]; /* Opcode table */ extern int pstsiz; /* size of pst */ extern struct sym rst[]; /* Register table */ extern int rstsiz; /* size of pst */ extern struct sym ust[]; /* User symbols */ extern struct sym *uptr; /* End of ust */ extern int page; /* Current page number */ extern int pline; /* Lines on the current page */ extern int listmode; /* Listing control */ extern int listaddr; /* Listing control */ extern int entaddr; /* .entry address */ extern FILE *src; /* Source */ extern FILE *lst; /* Listing */ extern FILE *obj; /* Object */ extern int lflag; /* -l flag */ extern int nflag; /* -n flag */ extern int sflag; /* -s flag */ extern int pass; /* Which pass? */ extern int skip; /* Skipping code lines */ extern int inif; /* in an if block of inif */ extern int lineno; /* Line number */ extern char *sptr; /* Source pointer */ extern char sbuf[]; /* Source buffer */ extern char *cptr; /* Listing code pointer */ extern char cbuf[]; /* Listing code buffer */ extern char *eptr; /* Error pointer */ extern char ebuf[]; /* Error buffer */ extern int cadr; /* Object address */ extern int crec; /* Object index */ extern char crbf[]; /* Object buffer */ extern char title[]; /* Title buffer */ extern int errcnt; /* number of errors encounterd */ extern int optype; /* Type of current operand */ #define getraw() (*sptr != '\0' ? *sptr++ : '\0') #define putback(c) ((c) != '\0' && --sptr < sbuf && abort()) #define getnb() (space(*sptr) ? _getnb() : getraw()) #define UNKNOWN 0 #define SPACE 0x01 #define LOWER 0x02 #define UPPER 0x04 #define OTHER 0x08 #define ALPHA (LOWER|UPPER|OTHER) #define DIGIT 0x10 extern char chartype[]; #define space(c) (chartype[(c)] & SPACE) #define lower(c) (chartype[(c)] & LOWER) #define upper(c) (chartype[(c)] & UPPER) #define alpha(c) (chartype[(c)] & ALPHA) #define digit(c) (chartype[(c)] & DIGIT) #define ucase(c) (lower(c) ? ((c) - ('a' - 'A')) : c) /* * Functions. */ extern struct sym *lookup(); /* Search pst */ extern struct sym *lookupreg(); /* Search rst */ extern struct sym *install(); /* Search ust */ SHAR_EOF if test 5187 -ne "`wc -c < 'asm.h'`" then echo shar: "error transmitting 'asm.h'" '(should have been 5187 characters)' fi fi echo shar: "extracting 'asm80.1'" '(531 characters)' if test -f 'asm80.1' then echo shar: "will not over-write existing file 'asm80.1'" else cat << \SHAR_EOF > 'asm80.1' .TH ASM80 1 "1 November 1986" .SH NAME asm80 \- Intel 8080 assembler .SH SYNOPSIS .B asm80 [ .B \-cln ] file .SH DESCRIPTION .I Asm80 is an assembler for Intel 8080 assembler programs. The input is taken from file.asm and the Intel hex output is in file.hex. The .B \-l flag enables the listing output, which goes to file.lst. If the .B \-c flag is specified, cross references are also generated. The .B \-n flag supresses hex output. .PP For example, .sp .ti +5 asm80 -l foo .sp assembles foo.asm, generating foo.hex and foo.lst. SHAR_EOF if test 531 -ne "`wc -c < 'asm80.1'`" then echo shar: "error transmitting 'asm80.1'" '(should have been 531 characters)' fi fi echo shar: "extracting 'asm80.doc'" '(12964 characters)' if test -f 'asm80.doc' then echo shar: "will not over-write existing file 'asm80.doc'" else cat << \SHAR_EOF > 'asm80.doc' A Cross Assembler for the Intel 8080-8085 With CPM[tm] syntax - by - David A. Klotzbach Introduction ASM80 is a two pass assembler for the Intel 8080 and the 8085. The input syntax is, in general, similar in style to the CPM[tm] assembler. It is also possible to use the assembler for the z80 since it is object code compatible with the 8080. CP/M is a registered trademark of Digital Research Inc. ASM80 User Manual The Cross Assembler Usage asm80 is invoked from as follows: asm80 [-n] [-l] file [file ...] The specified files are assembled separately and the object code is placed in a file (in the same directory) having the same name as the source file but with a filetype of HEX. The default filetype for source files is ASM. File type must not be specified. The optional -n argument causes the assembler to produce no object file. This option is primarily used to prevent creating a lot of useless object files when debugging the assembler; however, it may be of use when one wishes to simply check a file for errors. The optional -l argument causes the assembler to create a listing file of name <file>.LST. The object file is in standard CP/M HEX format. The title of the object file is always set to the first six characters of the source file name. Lexical Convention Assembler tokens consist of identifiers ('symbols', 'names','labels') , constants and operators. Identifier An identifier consists of a sequence of alphanumeric characters (including the period '.', at sign (@), and the question mark '?') the first of which may not be numeric. Only the first nine characters of the name are significant; the rest are discarded. Upper and lower case are treated as the same. - 3 - ASM80 User Manual Constants All numeric constants, octal, binary, hex or decimal, must start with a a digit 0 through 9. A HEX constant is a sequence of digits and the alpha characters A, B, C, D, E, and F. The number is truncated to 16 bits and interpreted in twos complement notation. If the base type symbol is omitted the base is taken to be decimal. The magnitude of the constant should be representable in 15 bits; i.e., be less than 32,768. b = Binary o,q = octal d = decimal H = hexidecimal A single character constant consists of the single quote (') followed by any ASCII character (except the newline) and terminated with another ('). The constant's value is the code for the character right justified in the word, with zeros on the left. Blanks and Tabs Blanks and tabs may be used freely between tokens, but may not appear within identifiers. A blank or a tab is required to separate adjacent tokens not otherwise separated. Comments The character ';' introduces a comment, which continues until the end of line. Comments are ignored by the assembler. The Location Counter The special symbol '$' is the location counter. Its value is the offset into the current programme section of the start of the statement in which it appears. - 4 - ASM80 User Manual Statements A program consists of a sequence of newline separated statements. There are three kinds of statements; null statements, assignment statements and keyword statements. Any statement may be preceeded by any number of labels. Labels A name label consists of an identifier followed by a colon (':'). The value of the label is set to that of the location counter. It is an error for the value of a label to change between pass 1 and pass2. Null Statements A null statement is just an empty line (which may have labels and be followed by a comment). Null statements are ignored by the assembler. Common examples of null statements are empty lines or lines consisting of only a label. A line containing only a ^L (line feed) is also considered as a null line. Assignment Statements An assignment statement consists of an identifier followed by the 'EQU' or 'SET' and an expression. The value of the identifier is set to that of the expression. Any symbol defined by an 'EQU' statement may be redefined, either by another assignment statement or by a label. Keyword Statements Keyword statements are the most common type; all of the machine operations and assembler pseudo operations are of this type. A keyword statement begins with one of the assembler's predefined keywords, followed by any operands required by that keyword. The 8085 instructions 'rim' and 'sim' are supported. - 5 - ASM80 User Manual Expressions An expression is a sequence of symbols representing a value. Expressions are made up of identifiers, constants, operators and parentheses. All binary operators have equal precidence and are executed in a strict left to right order (unless altered by parentheses). Types Every expression has a type determined by its operands. The types that will be met explicitly are: Undefined Upon first encounter, each symbol is undefined. A symbol may also become undefined if it is assigned to an undefined expression. It is an error to assemble an undefined expression in pass 2. Pass 1 allows assembly of undefined expressions, but phase errors may result if undefined expressions are used in certain contexts (i.e., in a ds). Absolute An absolute symbol is one defined untimately from a constant or from the difference of two relocatable values. Operators The operators are: '+' Addition '-' Subtraction '*' Multiplication '^' - XOR Exclusive or '%' - MOD Modulo '&' - AND Bitwise AND '|' - OR Bitwise OR '-' Unary negation '!' - NOT Unary ones complement '<' - SHL Shift left '>' - SHR Shift right Expressions may be grouped by means of parentheses. - 6 - ASM80 User Manual db expression [ , expression ] ... The expressions in the comma separated list are truncated to 8 bits and are assembled into successive bytes. The expressions must be absolute. Strings are also supported by this construct. dw expression [ , expression ] ... The expressions in the comma separated list are assembled into successive byte pairs, high byte first. ds expression This statement assembles into expression null bytes. The expression must be absolute. title s This statement allows the programmer to change the title line on the top of each listing page. Only the first 20 characters in the string are considered. The rest of the line is ignored. ORG expression The program counter is set equal to the value expression. It is not considered good form to set the porgram counter to a value less than the current one. There is no limit to the number of times this statement is used in a program. - 7 - ASM80 User Manual END expression This directive informs the assembler of the entry point into the program. OBJ expression (switch) A source code line may begin with '-obj' or '+obj' as a means to control the hex file generation. This is particularly usefull if the hex file is intended to be sent to a PROM programmer. By using the -obj expression, the hex file will not contain bytes addressed to declared ram areas ( ds, dw, etc). Error messages Syntactic or semantic errors in the source are reported by displaying the offending line on the console < your terminal> , preceeded by the appropriate error flag. a Addressing b Branching out of range c Constant expression e General error in expression m Multiply defined symbol n Error in number o Unknown opcode p Phasing / Port select q Questionable syntax t Byte truncation u Undefined z Code tabel overflow ' Character constant . Illegal use of DOT ( Parentheses inbalance Errors encountered in the accessing of files or in internal assembler operations are reported in english on the console. - 8 - Shortcomings and Caveats The assembler has some limitations. Some of the more important ones are listed below, and are classified as H (hard to fix), L (likely to remain), F (fixable, and likely to be fixed) and G (go away). L No macro facilities 8080 Instruction Summary - 9 - Psuedo Operations The following are extentions to the instructions set: 1) ORG expression 2) dw expression,expression,... , expression 3) db expression,expression,... , expression 4) ds expression 5) END expression 6) TITLE string - 10 - SHAR_EOF if test 12964 -ne "`wc -c < 'asm80.doc'`" then echo shar: "error transmitting 'asm80.doc'" '(should have been 12964 characters)' fi fi exit 0 # End of shell archive