/* Simple 6502 Assembler * * for C02 Compiler * * Uses DASM Syntax but * * supports 65C02 Op Codes */ /* DEBUG LEVELS * * $01 - Echo Input Lines * * $02 - Show Labels, Menonics, Operands * * $04 - Symbol Search/Set Details * * $08 - Individual Mnemonic Assembly * * $10 - Term Evaluation Details * ^ $20 - IF and SWITCH details * * $40 - Show Binary Output * ` * $80 - Parse Word and Lookup Details * ` */ #define DEBUG $00 //Print Debug Information //#include "a02lib.h02" - This will replace all the defs below #include #include #include #include #include #include #include #include alias char symtbl = $E000; //Global Symbol Table /* Address Mode Constants, Bit Masks, and Descriptions */ // 0 1 2 3 4 5 6 7 8 9 10 11 enum {ACMLT, IMMDT, ZPAGE, ZPAGX, ABSLT, ABSLX, ABSLY, IMPLD, INDCT, INDCX, INDCY, RELTV}; // 0 1 2 3 4 5 6 7 8 9 10 11 const char amodlo = {$01, $02, $04, $08, $20, $40, $80, $00, $00, $00, $00, $00}; const char amodhi = {$00, $00, $00, $00, $00, $00, $00, $01, $02, $04, $08, $10}; const char amdesc = {"Accumulator", "Immediate", "Zero Page", "Zero Page,X", "Absolute", "Absolute,X", "Absolute,Y", "Implied", "(Indirect)", "(Indirect,X)", "(Indirect),Y", "Relative", 0}; const char amdess = {"ACC","IMM","ZPG","ZPX","ABS","ABX","ABY","IMP", "IND","INX","INY","REL"}; /* Pseudo-Op Lookup Table */ struct pso {char token, name[5];}; const char psolst = {'B', "BYTE", 'H', "HEX", 'W', "WORD", '=', "EQU", 'F', "FILL", 'I', "INCL", 'S', "SUBR", 'B', "DC", 'F', "DS", 'A', "ALIG", '*', "ORG", 'P', "PROC", 'M', "ENDS", 'E', "END", $FF}; /* Op Code Lookup Table */ struct opc {char opcode, amdidx, name[5];}; const char opcalo = {$00, $00, $FE, $7D, $04, $04, $24, $26, $A6, $6E, $6C, $20, $20, $6E, $2C}; const char opcahi = {$01, $10, $0E, $00, $00, $10, $00, $00, $00, $00, $00, $06, $00, $00, $00}; const char opclst = { $00, 0, "BRK", $EA, 0, "NOP", $DB, 0, "STP", $CB, 0, "WAI", $CA, 0, "DEX", $88, 0, "DEY", $E8, 0, "INX", $C8, 0, "INY", $48, 0, "PHA", $08, 0, "PHP", $DA, 0, "PHX", $5A, 0, "PHY", $68, 0, "PLA", $28, 0, "PLP", $FA, 0, "PLX", $7A, 0, "PLY", $18, 0, "CLC", $D8, 0, "CLD", $58, 0, "CLI", $B8, 0, "CLV", $38, 0, "SEC", $F8, 0, "SED", $78, 0, "SEI", $AA, 0, "TAX", $A8, 0, "TAY", $BA, 0, "TSX", $8A, 0, "TXA", $98, 0, "TYA", $9A, 0, "TXS", $40, 0, "RTI", $60, 0, "RTS", $B0, 1, "BCS", $F0, 1, "BEQ", $30, 1, "BMI", $70, 1, "BVS", $90, 1, "BCC", $D0, 1, "BNE", $10, 1, "BPL", $50, 1, "BVC", $80, 1, "BRA", $A1, 2, "LDA", $61, 2, "ADC", $21, 2, "AND", $C1, 2, "CMP", $81, 2, "STA", $E1, 2, "SBC", $01, 2, "ORA", $41, 2, "EOR", $02, 3, "ASL", $22, 3, "ROL", $E2, 3, "INC", $42, 3, "LSR", $62, 3, "ROR", $C2, 3, "DEC", $07, 4, "RMB", $87, 4, "SMB", $0F, 5, "BBR", $8F, 5, "BBS", $10, 6, "TRB", $00, 6, "TSB", $E0, 7, "CPX", $C0, 7, "CPY", $A2, 8, "LDX", $82, 8, "STX", $20, 9, "BIT", $60, 10,"STZ", $4C, 11,"JMP", $14, 12,"JSR", $A0, 13,"LDY", $80, 14,"STY", $FF }; /* Op-Code Fixup Table */ struct opf {char token, opmod, opcode;}; const char opfix = { $20, $08, $89, $E0, $08, $E0, $C0, $08, $C0, $A0, $08, $A0, $A2, $08, $A2, $C2, $08, $3A, $E2, $08, $1A, $60, $0C, $9C, $60, $1C, $9E, $A2, $18, $BE, $82, $18, $BC, $4C, $0C, $4C, $4C, $11, $6C, $4C, $00, $7C, 0 }; /* Temporary and Index Variables */ char b, c, f, i, j, m, n, o, t, u; int v, w; /* Function Variables */ char found, match, opcode, opdfnd; //lookup(), asmpso(), asmopc() int opdval; //evlopd() values char hilo, opdrqd, prns, reqbyt, result; //evlopd() flags int addend; //adrslt() char digit; //evlhex() int term; //evltrm() /* Symbol Table Entries */ struct sym {char block, name[8], bytes; int value;}; struct sym symbol; //Current Symbol struct sym varble; //Symbol to Lookup int symcnt; //Number of Symbols int symptr; //Pointer to Next Table Entry char symflg; //Valid Symbol Value char blkcnt; //Number of Block Labels Generated char blknum; //Local Label Block Number (0 = Global) /* Input Variables */ char inplin[128]; //Input Buffer char inpidx; //Index into Input Buffer char eoinp; //End of Input int lineno; //Input File Line Number /* Output Variables */ char outlin[128]; //Output Buffer char outidx; //Index into Output Buffer /* Assembly Variables */ char label[8]; //Assembly Line Label char mcode[8]; //Generated Machine Code char mnmnc[12]; //Opcode Mnemonic char oprnd[128]; //Opcode Mnemonic char cmmnt[128]; //Assembly Line Comment char strng[128]; //Parsed String char word[128]; //Parsed Word char wrdlen; //Length of Parsed Word int mcdadr; //Machine Code Address char mcdidx; //Index into mcode[] char opridx; //Index into oprnd[] char endasm; //End Assembly char local,dot; //Local Symbol, Dot Prefix Flags char colon; //Colon after Label char token, opmod; //OpCode Token, Modifier char amflg, amidx; //Flag and Index - amodlo[], amodhi[] char amdlo, amdhi; //Addressing Modes char opvlo, opvhi; //Operand Value char zpflg; //ZeroPage Flag char hexadr[6]; //Current Address in Hexadecimal char bytstr[5]; //String Representation of Byte char orgset; //Origin Address Set int orgadr; //Origin Address int curadr; //Current Address int lstadr; //List Address /* Print Error Message and Exit * * Args: Y,X = Address of Eror Message */ void error() { putc('!'); putstr(); putln(" ERROR"); goto exit; } void lenerr(w) {setdst(word); strcpy(w); strcat(" TOO LONG"); error(word);} /* Read Line of Input from Console * * Populates: inplin[] - Line of Input * * Sets: inpidx - Length of Line * * Destroys: c - Input Character * * Returns: True if End of Input */ char readln() { inpidx = 0; do { c = getchr(); select (c) { case #RTNKEY: c = 0; case #ESCKEY: if (inpidx) c = 0; else return #TRUE; default: } inplin[inpidx] = c; inpidx++; if (inpidx:-) error("INPUT OVERFLOW"); } while (c); return #FALSE; } void prtchr(c) {if (c) putchr(c);} //Print Non-Null Character void prtbyt() {prbyte(); putchr(' ');} //Print Hexadecimal Word void echoln() {putchr('<'); putwrd(lineno); putln(inplin);} void init() { if (#DEBUG&2) putln("#STARTING ASSEMBLY"); lineno = 1; //Initialize Input File Line Number orgset = #FALSE; //Origin Not Set endasm = #FALSE; //End Assembly Fl symptr = &symtbl; blkcnt = 1; //Top level locals are Block 1 blknum = blkcnt; //because Block 0 is a global } /* Parse Word from Input Line * * Args: m = Maximum Length * * w = &Description of Word * * Populates: word[] * * Sets: wrdlen * * Updates: inpidx * * Returns: Word Found (TRUE/FALSE) */ char pword(m, w) { wrdlen = 0; while () { if (#DEBUG:-) putchr(inplin[inpidx]); c = touppr(inplin[inpidx]); if (c < 'A' or c > 'Z' and c <> '_') break; word[wrdlen] = c; wrdlen++; inpidx++; } word[wrdlen] = 0; //Terminate String if (m and wrdlen > m) lenerr(w); if (#DEBUG&4) {puts("PARSED "); puts(w); printf(setdst(word)," \"%s\"%n");} if (wrdlen) return #TRUE; else return #FALSE; } /* Skip Character in Input Line * * Args: c - Character to Skip * * Updates: inpidx * * Returns: c if found, else #FALSE */ int skpchr(c) { if (inplin[inpidx] == c) {inpidx++; return c;} else return #FALSE; } /* Skip Spaces in Input Line * * Updates: inpidx */ void skpspc() { while (inplin[inpidx]) { if (A > ' ') break; inpidx++; } } /* Copy Character from Input Line to Operand * * Args: c = character to copy (0 = any) * * Updates: inpidx * * Returns: character matched */ char cpychr(c) { o = touppr(inplin[inpidx]); if (c and o <> c) return #FALSE; if (opridx:+) {oprnd[opridx] = o; opridx++; } inpidx++; return #TRUE; } /* Check Origin Address */ void chkorg() { if (!orgset) error("ORIGIN NOT SET"); } /* Write Line of Machine Language Bytes */ void wrtmcd() { putwrd(mcdadr); for (i=0; i 7) {wrtmcd(); newlin();} //if (!mcdidx) mcdadr = curadr; if (#DEBUG&64) printf(setdst(b,curadr),"#OUT: %w $%x%n"); if (outidx<127) {outlin[outidx] = b; outidx++;} if (mcdidx<7) {mcode[mcdidx] = b; mcdidx++;} curadr++; } /* Output Machine Language Byte */ void outbyt() { outchr(); } /* Write Word to Output File */ void outwrd(w) { outchr(w); } /* Print Symbol Table */ void prtsym() { printf("%nSYMBOLS%nBLK SZ VALUE NAME%n"); usrptr = &symtbl; iacc(symptr); //end of symbol table for icmp() while (icmp(iacc(usrptr),symptr):-) { for (i=0; i<@symbol; i++) {symbol[i] = *usrptr; usrptr++;} putder(symbol.block); setdst(symbol.value); printf(symbol.bytes," %d %J "); if (symbol.block) putchr('.'); putln(symbol.name); } } /* Find Symbol in Table * * Uses: word = Symbol Name * * local = Local Symbol Flag * * blknum = Subroutine Block # * * Sets: varble = Contents of Entry * * Destroys: b, dstptr * * Returns: TRUE if Symbol was Found */ char fndsym() { if (#DEBUG&4) printf(setdst(local,word),"FNDSYM: WORD=\"%S\", LOCAL=%d - "); b = (local) ? blknum : 0; //Block level to match setdst(word); //For strcmp usrptr = &symtbl; iacc(symptr); //end of symbol table for icmp() while (icmp(iacc(usrptr),symptr):-) { varble.block = *usrptr; if (varble.block <> b) {usrptr = iaddc(@varble,usrptr); continue;} usrptr++; if (strcmp(usrptr)) {usrptr = iaddc(@varble-1,usrptr); continue;} for (i=1; i<@varble; i++) {varble[i] = *usrptr; usrptr++;} if (#DEBUG&4) putln("FOUND"); return #TRUE; } if (#DEBUG&4) putln("NOT FOUND"); return #FALSE; } /* Set Symbol Value and Size */ void setsym(b, v) { symbol.value = v; if (!b) b = (>symbol.value) ? 2 : 1; symbol.bytes = b; if (#DEBUG&4) { printf(setdst(symbol.block,symbol.name),"#SYMBOL %s IN BLOCK %d "); printf(setdst(symbol.bytes,symbol.value),"SET TO VALUE %i, SIZE %d%n"); } } /* Parse Label from Input Line * Sets: label[] = Label Name * local = '.' if Local else 0. ^ symbol.name = Label Name * symbol.value = Current Address * symbol.bytes = Size of Symbol Value * Updates: c */ void plabel() { local = (skpchr('.')) ? '.' : 0; //Check for Local Label if (#DEBUG&4) {puts("#PARSING "); if (local) puts("LOCAL "); putln("LABEL");} if (pword(8,"SYMBOL")) { setdst(label); strcpy(word); //if (#DEBUG&2) {putstr("#FOUND "); if (local) putstr("LOCAL "); putstr("LABEL "); putln(label);} symbol.block = (local) ? blknum : 0; setdst(symbol.name);strcpy(label); setsym(0, curadr); symflg = orgset; } else { label[0] = 0; if (#DEBUG&2) putln("#NO LABEL FOUND"); } colon = skpchr(':'); //Optional Colon after Label } /* Parse Mnemonic from Input Line * * Sets: mnmnc = Mnemonic * * word = Mnemonic * * wrdlen = Mnemonic Length * * Updates: inpidx * * Returns: Mnemonic Found (TRUE/FALSE) */ char pmnmnc() { skpspc(); //Skip Leading Spaces dot = skpchr('.'); //Optional Dot before Pseudo-Op if (pword(12,"MNEMONIC")) { for (i=0; i<=wrdlen; i++) mnmnc[i] = word[i]; if (#DEBUG&2) {putstr("#FOUND MNEMONIC "); putln(mnmnc);} } else { mnmnc[0] = 0; if (#DEBUG&2) putln("#NO MNEMONIC FOUND"); } } /* Look Up List Entry * * Args: amflg = get address modes * * srcptr = address of list * * Uses: mnmnc = mnemonic * * Sets: token = op code token * * amidx = address mode index * * Destroys: match * * Returns: TRUE if found */ char lookup(amflg, srcptr) { if (#DEBUG:-) printf(setdst(amflg,srcptr), "LOOKUP(%x,%w)"); while () { //Search Op-Code List if (#DEBUG:-) printf(setdst(srcptr)," SRCPTR=%w"); token = *srcptr; srcptr++; if (#DEBUG:-) printf(token, ", TOKEN=%d"); if (token == $FF) break; if (amflg) {amidx = *srcptr; srcptr++; if (#DEBUG:-) printf(amidx, ", AMDIDX=%d");} match = #TRUE; if (#DEBUG:-) newlin(); i = 0; //Offset into mnmnc while (*srcptr) { if (#DEBUG:-) { printf(setdst(*srcptr,srcptr)," (%w)=%d "); printf(i,", MNMNC[%d]="); putchr(mnmnc[i]); newlin(); } if (*srcptr <> mnmnc[i]) match = #FALSE; if (#DEBUG:-) prtbyt(match); i++; srcptr++; } if (match) return #TRUE; srcptr++; } return #FALSE; } /* Evaluate Binary Number */ void evlbin() { if (#DEBUG&16) putln("#EVALUATING BINARY NUMBER"); term = 0; cpychr('%'); while (isbdgt(inplin[inpidx])) { term<<; if (inplin[inpidx] & 1) term++; cpychr(0); } } /* Evaluate Character Constant */ void evlchr() { if (#DEBUG&16) putln("#EVALUATING QUOTED CHARACTER"); cpychr('\''); term = int(inplin[inpidx]); cpychr(0); cpychr('\''); } /* Evaluate Decimal Number */ int evldec() { if (#DEBUG&16) putln("#EVALUATING DECIMAL NUMBER"); term = 0; while (isdigt(inplin[inpidx])) { term = imultc(10, term); term = iaddc(inplin[inpidx] - '0', term); cpychr(0); } } /* Evaluate Hexadecimal Number */ int evlhex() { if (#DEBUG&16) putln("#EVALUATING HEXADECIMAL NUMBER"); term = 0; cpychr('$'); while (ishdgt(inplin[inpidx])) { digit = inplin[inpidx] - '0'; if (digit > 9) digit = digit - 7; term<<; term<<; term<<; term<<; term = iaddc(digit, term); cpychr(0); } } char evlsym() { local = cpychr('.'); //Check for Local Symbol if (!pword(8,"SYMBOL")) {if (local) error("INVALID SYMBOL"); else return;} if (#DEBUG&16) printf(setdst(word),"#EVALUATING SYMBOL \"%s\"%n"); for (i=0; i')) hilo = $FF;} if (hilo) prns = cpychr('('); if (#DEBUG&16) printf(hilo,"#HILO SET TO $%x%n"); result = evltrm(); if (#DEBUG&16) printf(setdst(result,term),"#EVLTRM RETURNED $%d, TERM=%i%n"); if (result) { opdval = term; while (cpychr('+')) { if (!evltrm()) break; opdval = iadd(setdst(opdval),term); } } if (#DEBUG&16) printf(setdst(opdval),"#CALCULATED OPDVAL %i%n"); if (hilo) { if (!result) error("ILLEGAL OPERAND"); if (prns) cpychr(')'); //Skip End Parenthesis if (hilo:-) opdval = int(>opdval); //Copy MSB to LSB opdval = int(opdval) error("VALUE TOO LARGE"); } else { if (#DEBUG&2) putln("#NO OPERAND"); if (opdrqd) error("OPERAND REQUIRED"); } return result, opdval; } /* Assemble EQU Pseudo-Op */ void asmequ() { if (#DEBUG&8) putln("#ASSEMBLING EQU PSEUDO-OP"); if (!label[0]) error("LABEL REQUIRED"); evlopd(#TRUE, #FALSE); setsym(0,opdval); symflg = #TRUE; } /* Assemble ORG Pseudo-Op */ void asmorg() { if (evlopd(#TRUE, #FALSE)) orgadr = opdval; if (symbol.name[0]) { symbol.value = orgadr; symbol.bytes = 2; } curadr = orgadr; lstadr = orgadr; orgset = #TRUE; symflg = #TRUE; } /* Assemble BYTE Pseudo-Op */ void asmbyt() { do { skpspc(); if (cpychr('"')) { //String Operand if (#DEBUG&2) putln("#ASSEMBLING .BYTE STRING OPERAND"); while (!cpychr('"')) {outchr(inplin[inpidx]); cpychr(0); } skpspc(); } else { if (evlopd(#TRUE, #TRUE)) outbyt(term) outbyt(>term); skpspc(); } while (ishdgt(inplin[inpidx])); } /* Assemble SUBROUTINE Pseudo-Op */ void asmsub() { blkcnt++; blknum = blkcnt; if (#DEBUG&2) printf(blknum,"#BLKNUM SET TO %d%n"); if (pword(7, "SUBROUTINE NAME")) { opridx=strcpy(setdst(oprnd),word); } else { if (#DEBUG&2) putln("NO SUBROUTINE NAME"); } } /* Assemble ENDSUBROUTINE Pseudo-Op */ void asmens() { blknum = 1; if (#DEBUG&2) printf(blknum,"#BLKNUM RESET TO %d%n"); } /* Assemble WORD Pseudo-Op */ void asmwrd() { do { evlopd(#TRUE, #FALSE); outwrd(opdval); } while (cpychr(',')); } /* Assemble ALIGN Pseudo-Op */ void asmaln() { //v = size, w = fill v = evlopd(#TRUE, #FALSE); if (icmp(iacc(v),&2):-) return; if (#DEBUG&2) printf(setdst(v),"ALIGNING TO %i BYTES%n"); w = imod(iacc(curadr),v); w = isub(iacc(v),w); //w = w - (curadr % v) if (#DEBUG&2) printf(setdst(w),"FILLING %i BYTES%n"); if (!icmp(w)) return; for (v=0; icmp(iacc(v),w):-; v++) outbyt(0); } /* Assemble FILL Pseudo-Op */ void asmfll() { w = evlopd(#TRUE, #FALSE); if (#DEBUG&2) printf(setdst(w),"FILLING %i BYTES%n"); for (v=0; icmp(iacc(v),w):-; v++) outbyt(0); } /* Assemble END Pseudo-Op */ void asmend() { endasm = #TRUE; if (#DEBUG&2) printf(endasm,"#ENDASM SET TO $%x%n"); } /* Assemble Pseudo-Op */ /* Uses: mnmnc = mnemonic * * Sets: token = op code token * * found = pseudo-op found * * Destroys: match * * Returns: TRUE if found */ char asmpso() { found = lookup(#FALSE, psolst); //Lookup Pseudo-Op if (!found) {if (dot) error("ILLEGAL PSEUDO-OP"); else return #FALSE;} if (#DEBUG&2) printf(token,"#ASSEMBLING PSEUDO-OP TOKEN='%c'%n"); skpspc(); select (token) { case '=': asmequ(); break; //EQU case '*': asmorg(); //ORG case 'B': asmbyt(); //BYTE case 'H': asmhex(); //HEX case 'W': asmwrd(); //WORD case 'F': asmfll(); //FILL case 'S': asmsub(); //SUBRoutine case 'M': asmens(); //ENDSubroutine //case 'I': asminf(); //INCLude //case 'P': asmprc(); //PROCessor case 'A': asmaln(); //ALIGn case 'E': asmend(); //END default: error("UNIMPLEMENTED"); } return #TRUE; } /* Check for Valid Addressing Mode */ int chkmod(m, f) { if (#DEBUG&2) { i = m; i<<; i<<; puts("#CHECKING ADDR MODE %"); putbin(amodhi[m]); putbin(amodlo[m]); putspc(); putsub(i,amdess); newlin(); } if (amodlo[m] & amdlo or amodhi[m] & amdhi) return #TRUE; if (f) error("ILLEGAL ADDRESS MODE"); return #FALSE; } /* Assemble Absolute/ZeroPage Indexed */ void asmidx() { if (cpychr('X')) { if (zpflg and chkmod(#ZPAGX)) {opmod = $14; return;} //ZeroPage,X if (chkmod(#ABSLX)) {opmod = $1C; return;} //Absolute,X } if (cpychr('Y')) { if (zpflg) { if (token == $82 or token == $A2) {opmod = $14; return;} //ZeroPage,Y } zpflg = #FALSE; opmod = $18; return; //Absolute,Y } chkmod(0); //Illegal Addressing Mode } /* Assemble Implied/Accumulator/Absolute/ZeroPage Mode Instruction */ void asmiaz() { opdfnd = evlopd(#FALSE, #FALSE); if (!opdfnd) { if (amidx and chkmod(#ACMLT, #TRUE)) opmod = $08; //Accumulator return; } if (>opdval) zpflg = #FALSE; else zpflg = #TRUE; if (#DEBUG&2) printf(zpflg,"#ZPFLG SET TO $%x%n"); if (zpflg and chkmod(#ZPAGE, #FALSE)) {opmod = $04; return;} //ZeroPage if (chkmod(#ABSLT, #TRUE)) {opmod = $0C; zpflg = #FALSE;} //Absolute if (cpychr(',')) asmidx(); //Indexed } /* Assemble Immediate Mode Instruction */ void asmimd() { if (#DEBUG&2) putln("#IMMEDIATE MODE"); evlopd(#TRUE, #TRUE); zpflg = #TRUE; opmod = $08; //Immediate } /* Assemble Indirect Mode Instruction */ void asmind() { if (#DEBUG&2) putln("#INDIRECT MODE"); zpflg = #TRUE; opdval = evlopd(#TRUE,#FALSE); if (cpychr(',') and cpychr('X') and chkmod(#INDCX)) {cpychr(')'); return;} if (!cpychr(')')) chkmod(0); //If no end paren - Illegal Addressing Mode if (cpychr(',') and cpychr('Y') and chkmod(#INDCY)) {opmod = $10; return;} if (chkmod(#INDCT)) opmod = $11; //(Indirect) if (token == $4C) {zpflg = #FALSE;} //JMP (Indirect Absolute) } /* Calculate Branch Offset */ void asmbro() { if (#DEBUG&2) putln("#CALCULATING BRANCH OFFSET"); skpspc(); if (inplin[inpidx]=='.' or isalph(A)) { if (#DEBUG&4) putln("#PARSING LABEL"); if (evlsym()) w = isub(isub(iacc(varble.value),curadr),v); return; } if (cpychr('+')) {w = evlopd(#TRUE,#FALSE); return;} if (cpychr('-')) {w = ineg(evlopd(#TRUE,#FALSE)); return;} if (#DEBUG&4) putln("#PARSING ADDRESS"); w = isub(isub(iacc(evlopd(#TRUE,#FALSE)),curadr),v); } /* Assemble Branch Opcode */ void asmbrn(zpflg) { if (#DEBUG&2) putln("#RELATIVE MODE"); w = 0; //Offset if (zpflg) v = 2; else v = 3; //Offset Adjustment asmbro(); if (#DEBUG&2) printf(setdst(w),"#BRANCH OFFSET IS $%w%n"); if (>w and A <> $FF) error("BRANCH OUT OF RANGE"); opdval = int(opdval ) error("OPERAND TOO LARGSE"); opcode = fixopc(); //Fixup Opcode if (#DEBUG&2) printf(opcode, "#WRITING OPCODE $%x%n"); outchr(opcode); if (#DEBUG&2 and opdfnd) printf(setdst(opdval), "#WRITING OPDVAL %i%n"); if (opdfnd) {if (zpflg) outbyt(= ' ') { cmmnt[i] = inplin[inpidx]; i++; inpidx++; } cmmnt[i] = 0; //Terminate Comment if (#DEBUG&2) {if (i) {putstr("#COMMENT: "); putln(cmmnt);} else putln("#NO COMMENT FOUND");} } /* Append Symbol` to Symbol Table * * Uses: symbol * * Sets: i = @symbol * * dstptr = End of Table * * Updates: symptr = End of Table * * Returns: End of Table Address */ void addsym() { if (!symbol.value) error("ORIGIN NOT SET"); dstptr = symptr; for (i=0; i<@symbol; i++) { *dstptr = symbol[i]; dstptr++; } symptr = dstptr; if (#DEBUG&4) printf(setdst(symbol.name),"#ADDED SYMBOL \"%s\" TO TABLE%n"); } /* Print Listing Line */ void prlist() { putc('|'); prtchr(local); putstr(label); prtchr(colon); putspc(); prtchr(dot); putstr(mnmnc); putspc(' '); if (opridx) putstr(oprnd); putln(cmmnt); } void asmlin() { lstadr = curadr; //Set List Address opridx = 0; //Clear Operand String outidx = 0; //Clear Output Buffer mcdidx = 0; //Clear Macbine Code inpidx = 0; //Initialize Line Buffer Index plabel(); //Parse Label pmnmnc(); //Parse Mnemonic if (mnmnc[0]) { if (!asmpso()) asmopc(); //Assemble Pseudo-Op or Op-Code oprnd[opridx] = 0; //Terminste oprnd } pcmmnt(); //Parse Comment if (label[0]) { if (!symflg) error("INVALID ADDRESS"); addsym(); //Add Label to Table } //if (mcdidx) wrtmcd(); //Write Machine Code prlist(); } main: init(); //Initialize Assembly Variables goto tests; goto tests; while (!readln()) { if (#DEBUG&1) echoln(); asmlin(); if (endasm) break; lineno++; } prtsym(&symtbl); goto exit; /*======================================================*/ /* Everything below here is tests for various functions */ //Copy Arg String to inplin void setln(w) { inpidx = 0; setdst(inplin); strcpy(w); putstr(">>"); putln(inplin); } void slabel() {setln(); plabel();} void pout() { puts(" OUTLIN: "); for (i=0; iBIG, \"STRING\" "); tasm(" HEX 0 1 2 F 10 F0 FEEF "); tasm(" WORD 1, 1001, %11111, $F00F, TOP"); tasm(" FILL 300"); tasm(" ALIGN 256"); tasm(" DS 20"); tasm(" SUBR MYLIB"); tasm(".YOKEL BYTE 2,2,2,2"); tasm(" SUBROUTINE"); tasm(".YOKEL BYTE 3,3,3,3"); tasm(" ENDSUB"); tasm(" END"); tasm(" BRK ;$00"); tasm(" RTS ;$60"); tasm(" NOP ;$EA"); tasm(" JMP $C4 ;$4C $C4 $00"); tasm(" JMP $C44C ;$4C $C4 $4C"); tasm(" JMP ($C6) ;$6C $C6 $00"); tasm(" JMP ($C66C) ;$6C $C6 $6C"); tasm(" LDA $01 ;$A5 $01"); tasm(" LDA $0400 ;$AD $00 $04"); tasm(" LDA #89 ;$A9 $59"); tasm(" LDA ($1A,X) ;$A1 $1A"); tasm(" LDA ($1B),Y ;$B1 $1B"); tasm(" LDA $5B,X ;$B5 $5B"); tasm(" LDA $B99B,Y ;$B9 $9B $B9"); tasm(" LDA $BDDB,X ;$BD $DB $BD"); tasm("BRANCH:"); tasm(" BCS BRANCH ;$B0 $FE"); tasm(" BCC BRANCH ;$90 $FB"); tasm(" BEQ -128 ;$F0 $80"); tasm(" BNE +127 ;$D9 $7F"); tasm(" BPL $0500 ;$10 $??"); tasm(" LSR ;$4A"); tasm(" LSR $64 ;$46 $64"); prtsym(); goto exit; // $A1, 2, "LDA", $61, 2, "ADC", $21, 2, "AND", $C1, 2, "CMP", $81, 2, "STA", // $E1, 2, "SBC", $01, 2, "ORA", $41, 2, "EOR", $02, 3, "ASL", $22, 3, "ROL", // $E2, 3, "INC", $42, 3, "LSR", $62, 3, "ROR", $C2, 3, "DEC", $07, 4, "RMB", // $87, 4, "SMB", $0F, 5, "BBR", $8F, 5, "BBS", $10, 6, "TRB", $00, 6, "TSB", // $E0, 7, "CPX", $C0, 7, "CPY", $A2, 8, "LDX", $82, 8, "STX", $20, 9, "BIT", // $60, 10,"STZ", $4C, 11,"JMP", $14, 12,"JSR", $A0, 13,"LDY", $80, 14,"STY", // 'I', "INCL", 'S', 'F', "DS", 'P', "PROC",