/* Simple 6502 Assembler for CC02 Compiler * * Uses DASM Syntax but supports 65C02 Op Codes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define LBLSIZ 8 //Maximum Symbol Length #define WRDSIZ 16 //Maximum Parsed Word Length const char debug = #TRUE; char inplin[#STRSIZ]; //Input Buffer char inpidx; //Pointer into Input Buffer int lineno; //Input File Line Number int savlno; //Line Number (Saved) char pass2; //Assembler Pass 2 flag char endasm; //End Assembly Flag char label[#WRDSIZ]; //Assembly Line Label char mnmnc[#WRDSIZ]; //Opcode Mnemonic char oprnd[#STRSIZ]; //Operand Text char cmmnt[#STRSIZ]; //Assembly Line Comment char mcode[#STRSIZ]; //Generated Bytes char strng[#STRSIZ]; //Parsed String char inpnam[#STRSIZ]; //Input File Name char outnam[#STRSIZ]; //Output File Name char lstnam[#STRSIZ]; //List File Name char incnam[#STRSIZ]; //Include File Name char inpfil; //Input File Channnel char outfil; //Output File Channnel char lstfil; //List File Channnel char incfil; //Include File Channnel int orgadr; //Origin Address int curadr; //Current Address int lstadr; //List Address char orgflg; //Origin Address Flag char curflg; //Current Address Flag struct sym { char name[#LBLSIZ]; //Symbol Name char block; //Local Lable Block ID char bytes; //Value Size, High Bit set if Referenced int value; //Symbol Value char refrd; //Referenced }; struct sym symbol; //Current Symbol struct sym symfnd; //Symbol found by fndsym struct sym symprt; //Symbol to print int symcnt; //Number of Global Labels char blockc; //Number of Block Labels Generated char blockn; //Local Label Block ID (0 = Global) int symbgn; //Start Address of Symbol Table int symend; //End Address of Symbol Table int symptr; //Pointer to entry in Symbol Table char token, opmod; //OpCode Token, Modifier char zpage; //Zero Page Flag int amode, opval; //Address Mode Mask, Operand Value char aa,bb,cc,dd,ff,mm,xx,yy,zz; int ii, jj, yx; /* Print Error Message and Exit */ void xerror() { printf(); //Implicit Arguments dstptr = lineno; if (dstptr) printf(" IN LINE %d"); newlin(); goto exit; } /* Open File with Error Checking */ char opnfil(aa, yx) { if (debug) {setdst(yx); printf(aa, "OPENING FILE '%s' WITH MODE %x%n");} zz = fopen(aa, yx); if (!zz) {setdst(yx); xerror("ERROR OPENING FILE '%s'%n");} if (debug) printf(zz, "FILE OPENED ON CHANNEL %d%n"); return zz; } /* Copy Character to Operand * * Args: cc - Character to Skip * * Updates: inpidx * * Returns: #TRUE if copied */ char cpychr(cc) { if (cc and touppr(inplin[inpidx]) <> cc) return #FALSE; aa = inplin[inpidx]; strapd(touppr(aa), oprnd); inpidx++; return #TRUE; } /* Skip Character in Input Line * * Args: c - Character to Skip * * Updates: inpidx */ int skpchr(cc) { if (inplin[inpidx] == cc) {inpidx++; return #TRUE;} else return #FALSE; } /* Skip Spaces in Input Line * * Updates: inpidx */ void skpspc() { do {} while (skpchr(' ')); } /* Parse Word from Input Line * * Args: skip - Skip Spaces Flag * * &word - Buffer for Word * * Sets: dstptr - Buffer Address * * Updates: inpidx * * Affects: aa, zz * * Returns: Word Found (TRUE/FALSE) */ char pword(aa, yx) { zz = 0; dstptr = yx; if (aa) skpspc(); while (isalnu(inplin[inpidx])) { *dstptr = touppr(inplin[inpidx]); inpidx++; dstptr++; zz++; } *dstptr = 0; //Terminate String dstptr = yx; if (zz) return #TRUE; else return #FALSE; } /* Print Symbol Structure * * Args: &sym - Address of sym Struct * * Sets: symprt - Contents of struct * * Affects: dtsptr, jj */ void prtsym(jj) { setdst(symprt); memcpy(@symprt, jj); setdSt(symprt.name); printf(symprt.block,"SYMBOL[BLOCK=%d, NAME=%s, "); setdst(symprt.value); printf(symprt.bytes,"SIZE=%d, VALUE=$%w"); printf(symprt.refrd,", REFRD=%x]%n"); } /* Set memory block to symmtbl * * Args: A = 0 - Add Symbol * * <> 0 - Read Symbols * * Sets: blkbgn, blkend * * blklen, blkptr */ void symblk(blkend) { if (A|0) {blkptr = symbgn; blkend = symptr;} else {blkptr = symptr; blkend = symend;} blkbgn = symbgn; blklen = @symbol; } /* Find Symbol in Symbol Table * * Args: char aa - Local Label Block Number * * int yx - Pointer to Symbol Name * * Sets: blkptr - Pointer to Entry in Table * * Populates: symfnd - Matching Symbol from Table * * Preserves: dstptr; * * Affects: aa, ff, ii, yx * * Returns: #TRUE if found, otherwise #FALSE */ char fndsym(aa, yx) { ii = dstptr; setdst(yx); //Set srring for printf if (debug) printf(aa, " SEARCHING FOR SYMBOL %s IN BLOCK %d\n"); setdst(symfnd); //Set Struct for blkstr() to populate symblk($FF); blkrst(); //Reading Symbol Table while() { ff = blkstr(@symfnd,yx); if (!ff) break; if (symfnd.block == aa) break; } if (debug) { if (ff) {puts(" FOUND "); prtsym(symfnd);} else putln(" NOT FOUND"); } dstptr = ii; return ff; } /* Set Symbol Value and Size */ void setsym(aa, jj) { symbol.value = jj; if (aa) symbol.bytes = aa; else symbol.bytes = (>jj) ? 2 : 1; symbol.refrd = curflg ^ $FF; if (debug) {puts(" SET "); prtsym(symbol);} } /* Parse Label from Input Line * * Sets: label - parsed label * * Updates: inoidx * * Affects: aa, bb, ff, ii, jj, yx * * Returns: Label Found (TRUE/FALSE) */ char plabel() { if (debug) putln("PARSING LABEL"); bb = (skpchr('.')) ? blockn : 0; //Local Label Block Number ff = pword(#FALSE, label); //Sets dstptr to &label if (debug) { if (ff) printf(bb," FOUND BLOCK %d LABEL %s%n"); else putln(" NO LABEL FOUND"); } skpchr(':'); //Skip Optional Label Terminator if (ff and !pass2) { if (label[0] and fndsym(bb, label)) xerror("DUPLICATE LABEL %S ENCOUNTERED%n"); if (debug) printf(" INITIALIZING SYMBOL %s%n"); symbol.block = bb; if (strlen(label) > #LBLSIZ) xerror("LABEL %S TOO LONG\n"); setdst(symbol.name); strcpy(label); setsym(0, curadr); } if (bb) strppd('.', label); skpspc(); //Skip to Mnemonic, Comment, or EOL return ff; } /* Assemble Pseudo-Op */ int asmpso(dd) { setdst(mnmnc); if (strcmp("END")) return #FALSE; endasm = #TRUE; return; // if (!lkpopc(psolst) and !dd ) return #FALSE; // skpspc(); // setdst(mnmnc); if (debug) printf(token, "ASSEMBLING PSEUDO-OP %s, TOKEN '%c'%n"); // select (token) { // case '=': asmequ(); //EQU // case 'B': asmbyt(); //BYTE or DC // case 'H': asmhex(); //HEX // case 'W': asmwrd(); //WORD // case 'F': asmfll(); //FILL or DS // case 'S': asmsub(); //SUBRoutine // case 'M': asmens(); //ENDSubroutine // case 'I': asminf(); //INCLude // case '*': asmorg(); //ORG // case 'P': asmprc(); //PROCessor // case 'E': asmend(); //END // case 'A': asmaln(); //ALIGn // default: xerror("Undefined Pseudo-Op %s%n"); // } // if (dd) strppd('.', mnmnc); // return #TRUE; } /* Assemble Opcode * Uses: dd - Dot Prefix*/ char asmopc() { if (debug) printf(" ASSEMBLING MNEMONIC %s%n"); opmod = 0; if (asmpso()) return; //Check For/Assemble Pseudo-Op // if (lkpopc(opclst) == FALSE) xerror("Invalid Mnemonic %s\n", mnmnc); // if (debug) printf("Assembling Opcode Token 0x%02X, ", token); // if (debug) printf("Addressing Mode Mask 0x%04X\n", amode); // skpspc(); // if (amode == RELTV) asmbrn(TRUE); //Branch (Relative) Instruction // else if (amode == 0x0004 || amode == 0x1004) asmzpr(); //Branch (Relative) Instruction // else if (cpychr('#')) asmimd(); //Assemble Implied Instruction // else if (cpychr('(')) asmind(); //Assemble Indirect Instruction // else asmiaz(); //Assemble Implied/Accumulator/Absolute/ZeroPage Instruction // if (debug) dbgopc(); // int opcode = fixopc(); // if (debug) printf("Writing OpCode $%02X\n", opcode); // outbyt(opcode); // if (debug) printf("Writing %s Operand %d\n", zpgabs[-zpage], opval); // if (opval >= 0) { // if (zpage) outbyt(opval); //Byte Operand // else outwrd(opval); //Word Operand // } // return TRUE; } /* Parse Opcode Mnemonic from Input Line * Sets: mnmnc * Updates: inpidx * Returns: Mnemonic Found (TRUE/FALSE) */ char pmnmnc() { if (debug) putln("PARSING MNEMONIC"); dd = cpychr('.'); //Optional Dot before Pseudo-Op mm = pword(#TRUE, mnmnc); oprnd[0] = 0; //Initialize Operand if (mm) asmopc(dd); //Assemble Opcode else putln(" NONE FOUND"); return mm; } /* Print Input Line for Debugging */ void pinlin() { dstptr = lineno; printf(pass2+1, "> %d%j"); dstptr = curadr; printf(" %w "); puts(inplin); } /* Add Label to Symbol Table */ void addsym() { if (symbol.refrd) xerror("ORIGIN NOT SET"); symblk(0); blkput(@symbol, symbol); symptr = blkptr; if (debug) {puts("ADDED "); prtsym(symbol);} } /* Assemble Input File (Two Pass) * * Args: pass - Assembly Pass (1 or 2) * * Requires: inpfil - Input File Pointer * * Uses: inplin - Input Line Buffer * * lineno - Input File Line Number */ void asmfil(pass2) { endasm = #FALSE; //Reset End Assembly Flag if (debug) {printf(pass2+1,"Assembling Pass %d%n");} lineno = 1; //Initialize Input File Line Number blockc = 0; blockn = 0; //Initialize Local Block Count and Number orgadr = 0; orgflg = 0; //Origin Address Not Set curadr = &$1000; curflg = $FF; //Current Address Not Set while () { aa = (incfil) ? incfil : inpfil; zz = fgets(aa, inplin); if (endasm or !zz) break; //{if (incfil) {clsinc(); continue;} else break;} if (debug) pinlin(); inpidx = 0; lstadr = curadr; //Set List Address mcode[0] = 0; //Clear Generated Macbine Code plabel(); //Parse Label pmnmnc(); //Parse Mnemonic // pcmmnt(); //Parse Comment if (!pass2 and label[0]) addsym(); //Add Label to Table // if (passno == 2) { // if (lstadr < 0) hexadr[0] = 0; else sprintf(hexadr, "%04X", lstadr); // fprintf(lstfil, "%05d %-4s %-9s%-7s %-5s %-16s %s\n", lineno, hexadr, mcode, label, mnmnc, oprnd, cmmnt ); // fflush(lstfil); //Flush Output Buffer in case of Segmentation Fault // } lineno++; // if (incnam[0] && incfil == NULL) opninc(); //Open Include File } } /* Print Symbol Table */ /* Print Symbol Table */ void prttbl() { putln("Symbol Table"); putln("Block Name Size Value Rfd"); blkptr = symbgn; while () { blkget(@symprt, symprt); if (!symprt.name[0]) break; cc = (symprt.refrd) ? '*' : ' '; printf(symprt.block,"%r "); putpad(9, symprt.name); setdst(symfnd.value); printf(symfnd.bytes," %r %j "); putchr(cc); newlin(); } } /* Read Command Line Arguments and Open Files */ void doargs() { if (debug) {setdst(sysbfr); printf("PARSING ARGUMENTS \"%s\"%n");} aa = argset(); if (aa) xerror("NO ARGUMENTS SPECIFIED"); aa = argget(inpnam); if(!aa) xerror("INPUT FILE NOT SPECIFIED"); if (debug) printf(" PARSED INPNAM \"%s\"%n"); aa = argget(outnam); //if(!aa) xerror("OUTPUT FILE NOT SPECIFIED"); if (debug) printf(" PARSED OUTNAM \"%s\"%n"); aa = argget(lstnam); if (debug) printf(" PARSED LSTNAM \"%s\"%n"); } main: symbgn = &$8000; symend = &$A000; symptr = symbgn; //Set up Symbol Table symblk($FF); blkset(0); //Initialize Symbol Table doargs(); //Read File Names and Options from Command Line Arguments inpfil = opnfil(0,inpnam); asmfil(0); fclose(inpfil); prttbl(); //if (lstfil && symcnt) prttbl(); //Print Symbol Table putln("ASSEMBLY COMPLETE"); goto exit;