C02/cc02src/asm02.c02

385 lines
12 KiB
Plaintext

/* Simple 6502 Assembler for CC02 Compiler *
* Uses DASM Syntax but supports 65C02 Op Codes */
#include <stddef.h02>
#include <stdlib.h02>
#include <args.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();
}
}
/* 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;