mirror of https://github.com/RevCurtisP/C02.git
Initial commit of asm02.c02
This commit is contained in:
parent
8e9beb39dc
commit
1666f1a508
|
@ -0,0 +1,368 @@
|
|||
/* Simple 6502 Assembler for CC02 Compiler *
|
||||
* Uses DASM Syntax but supports 65C02 Op Codes */
|
||||
|
||||
#include <stddef.h02>
|
||||
#include <stdlib.h02>
|
||||
#include <intlib.h02>
|
||||
#include <ctype.h02>
|
||||
#include <stdio.h02>
|
||||
#include <stdiox.h02>
|
||||
#include <memory.h02>
|
||||
#include <string.h02>
|
||||
#include <stringl.h02>
|
||||
#include <stringm.h02>
|
||||
#include <block.h02>
|
||||
#include <fileio.h02>
|
||||
|
||||
#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 or >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;
|
||||
|
Loading…
Reference in New Issue