From 1666f1a50826a843502e988268e98e6d5942a01e Mon Sep 17 00:00:00 2001 From: Curtis F Kaylor Date: Sat, 25 Sep 2021 15:30:18 -0400 Subject: [PATCH] Initial commit of asm02.c02 --- cc02src/asm02.c02 | 368 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 cc02src/asm02.c02 diff --git a/cc02src/asm02.c02 b/cc02src/asm02.c02 new file mode 100644 index 0000000..cd43b88 --- /dev/null +++ b/cc02src/asm02.c02 @@ -0,0 +1,368 @@ +/* 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 + +#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(); + } +} + +main: + symbgn = &$8000; symend = &$A000; symptr = symbgn; //Set up Symbol Table + symblk($FF); blkset(0); //Initialize Symbol Table + setdst(inpnam); strcpy("opcodes.a02"); + inpfil = opnfil(0,inpnam); + asmfil(0); + fclose(inpfil); + prttbl(); + //if (lstfil && symcnt) prttbl(); //Print Symbol Table + putln("ASSEMBLY COMPLETE"); + + goto exit; + \ No newline at end of file