mirror of
https://github.com/RevCurtisP/C02.git
synced 2024-11-25 06:31:25 +00:00
Created Assembler a02.c
This commit is contained in:
parent
3a7224ce9a
commit
9478d41299
572
a02.c
Normal file
572
a02.c
Normal file
@ -0,0 +1,572 @@
|
|||||||
|
/* Simple 6502 Assembler *
|
||||||
|
* for C02 Compiler *
|
||||||
|
* Uses DASM Syntax but *
|
||||||
|
* supports 65C02 Op Codes */
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include "a02.h"
|
||||||
|
|
||||||
|
#define DEBUG TRUE
|
||||||
|
|
||||||
|
enum otypes {BINFIL, PRGFIL}; //Object File Types
|
||||||
|
|
||||||
|
char objtyp; //Object File Type
|
||||||
|
int orgadr; //Origin Address
|
||||||
|
int curadr; //Current Address
|
||||||
|
int lstadr; //List Address
|
||||||
|
|
||||||
|
struct sym {int block; char name[MAXSYM]; int bytes, value;};
|
||||||
|
struct sym symbol; //Current Symbol
|
||||||
|
struct sym symtbl[MAXGLB]; //Global Symbol Table
|
||||||
|
int symcnt; //Number of Global Labels
|
||||||
|
int blknum; //Local Label Block Number (0 = Global)
|
||||||
|
|
||||||
|
char label[MAXSTR]; //Assembly Line Label
|
||||||
|
char mnmnc[MAXSTR]; //Opcode Mnemonic
|
||||||
|
char oprnd[MAXSTR]; //Opcode Mnemonic
|
||||||
|
char cmmnt[MAXSTR]; //Assembly Line Comment
|
||||||
|
char mcode[MAXSTR]; //Generated Bytes
|
||||||
|
char strng[MAXSTR]; //Parsed String
|
||||||
|
|
||||||
|
unsigned char token, opmod; //OpCode Token, Modifier
|
||||||
|
unsigned int amode; //Addressing Modes
|
||||||
|
int zpage, opval; //ZeroPage Flag, Operand Value
|
||||||
|
|
||||||
|
char hexadr[6]; //Current Address in Hexadecimal
|
||||||
|
char bytstr[5]; //String Representation of Byte
|
||||||
|
|
||||||
|
char inplin[MAXSTR]; //Input Buffer
|
||||||
|
char *linptr; //Pointer into Input Buffer
|
||||||
|
int lineno; //Input File Line Number
|
||||||
|
int opridx; //Index into Operand
|
||||||
|
int passno; //Assembler Pass Number (1 or 2)
|
||||||
|
|
||||||
|
char prgnam[256]; //Assembler Path and Name (from Command Line)
|
||||||
|
char inpnam[256]; //Input File Name
|
||||||
|
char outnam[256]; //Output File Name
|
||||||
|
char lstnam[256]; //List File Name
|
||||||
|
FILE *inpfil; //Input File Pointer
|
||||||
|
FILE *outfil; //Output File Pointer
|
||||||
|
FILE *lstfil; //List File Pointer
|
||||||
|
|
||||||
|
/* Print Error Message and Exit */
|
||||||
|
void xerror(char* format, char *s) {
|
||||||
|
if (lineno) fprintf(stderr, "%04d: ", lineno);
|
||||||
|
fprintf(stderr, format, s);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip Character in Input Line *
|
||||||
|
* Args: c - Character to Skip *
|
||||||
|
* Updates: linptr */
|
||||||
|
int skpchr(char c) {
|
||||||
|
if (*linptr == c) {linptr++; return TRUE;}
|
||||||
|
else return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip Spaces in Input Line *
|
||||||
|
* Updates: linptr */
|
||||||
|
void skpspc(void) {
|
||||||
|
while (*linptr && *linptr <= ' ') linptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Word from Input Line *
|
||||||
|
* Args: skip - Skip Spaces Flag *
|
||||||
|
* *word - Buffer for Word *
|
||||||
|
* Updates: linptr *
|
||||||
|
* Returns: Word Found (TRUE/FALSE) */
|
||||||
|
int pword(int skip, char* word) {
|
||||||
|
int wrdlen = 0;
|
||||||
|
if (skip) skpspc();
|
||||||
|
while (isalnum(*linptr)) {
|
||||||
|
word[wrdlen++] = toupper(*linptr);
|
||||||
|
linptr++;
|
||||||
|
}
|
||||||
|
word[wrdlen] = 0; //Terminate String
|
||||||
|
if (wrdlen) return TRUE; else return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sym *fndsym(int block, char* name) {
|
||||||
|
for (int i=0; i < symcnt; i++) {
|
||||||
|
if (symtbl[i].block != block || strcmp(symtbl[i].name,name)) continue;
|
||||||
|
return &symtbl[i];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Symbol Value and Size */
|
||||||
|
void setsym(int value, int bytes) {
|
||||||
|
if (DEBUG) printf("Setting Symbol %s to %d\n", symbol.name, value);
|
||||||
|
symbol.value = value;
|
||||||
|
if (bytes) symbol.bytes = bytes;
|
||||||
|
else symbol.bytes = (value > 0xFF) ? 2 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Label from Input Line
|
||||||
|
* Sets: label
|
||||||
|
* Updates: linptr
|
||||||
|
* Returns: Label Found (TRUE/FALSE) */
|
||||||
|
int plabel(void) {
|
||||||
|
if (DEBUG) puts("Parsing Label");
|
||||||
|
int block = (skpchr('.')) ? blknum : 0; //Local Label Block Number
|
||||||
|
int found = pword(FALSE, label); //Parse Word without Skipping Spaces
|
||||||
|
if (DEBUG) {
|
||||||
|
if (found) printf("Found Label %s\n", label);
|
||||||
|
else puts("No Label Found");
|
||||||
|
}
|
||||||
|
skpchr(':'); //Skip Optional Label Terminator
|
||||||
|
if (found && passno == 1) {
|
||||||
|
if (label[0] && fndsym(block, label)) xerror("Duplicate Label %s Encountered\n", label);
|
||||||
|
if (DEBUG) printf("Initializing Symbol %s\n", label);
|
||||||
|
symbol.block = block;
|
||||||
|
strcpy(symbol.name, label);
|
||||||
|
setsym(curadr, 0);
|
||||||
|
}
|
||||||
|
if (block) {
|
||||||
|
for (int i=strlen(label)+1; i; i--) label[i] = label[i-1];
|
||||||
|
label[0] = '.';
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy Character to Operand and Increment */
|
||||||
|
int cpychr(int c) {
|
||||||
|
if (c && toupper(*linptr) != c) return FALSE;
|
||||||
|
oprnd[opridx++] = toupper(*linptr++);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate Binary Number */
|
||||||
|
int evlbin() {
|
||||||
|
int result = 0;
|
||||||
|
cpychr('%');
|
||||||
|
while (isdigit(*linptr)) {
|
||||||
|
if (*linptr > '1') break;
|
||||||
|
result = (result << 1) + *linptr - '0';
|
||||||
|
cpychr(0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate Binary Number */
|
||||||
|
int evlchr() {
|
||||||
|
int result = 0;
|
||||||
|
cpychr('\'');
|
||||||
|
result = *linptr;
|
||||||
|
cpychr(0);
|
||||||
|
cpychr('\'');
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate Decimal Number */
|
||||||
|
int evldec() {
|
||||||
|
int result = 0;
|
||||||
|
while (isdigit(*linptr)) {
|
||||||
|
result = result * 10 + *linptr - '0';
|
||||||
|
cpychr(0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate Hexadecimal Number */
|
||||||
|
int evlhex() {
|
||||||
|
int result = 0;
|
||||||
|
cpychr('$');
|
||||||
|
while (isxdigit(*linptr)) {
|
||||||
|
int digit = *linptr - '0';
|
||||||
|
if (digit > 9) digit = digit - 7;
|
||||||
|
result = (result << 4) + digit;
|
||||||
|
cpychr(0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate Symbol */
|
||||||
|
struct sym *evlsym() {
|
||||||
|
char name[MAXSTR];
|
||||||
|
int block = (cpychr('.')) ? blknum : 0;
|
||||||
|
pword(TRUE, name);
|
||||||
|
for (int i=0; name[i]; i++) oprnd[opridx++] = name[i];
|
||||||
|
struct sym *result = fndsym(block, name);
|
||||||
|
if (passno == 2 && result == NULL) xerror("Undefined Symbol %s\n", name);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate Term in Operand */
|
||||||
|
int evltrm() {
|
||||||
|
int result;
|
||||||
|
skpspc();
|
||||||
|
if (isalpha(*linptr) || *linptr == '.') {
|
||||||
|
struct sym *target = evlsym();
|
||||||
|
result = (target) ? target->value : 0x100;
|
||||||
|
}
|
||||||
|
else if (isdigit(*linptr))
|
||||||
|
result = evldec();
|
||||||
|
else switch(*linptr) {
|
||||||
|
case '$': result = evlhex(); break;
|
||||||
|
case '%': result = evlbin(); break;
|
||||||
|
case '\'': result = evlchr(); break;
|
||||||
|
default: result = -1;
|
||||||
|
}
|
||||||
|
skpspc();
|
||||||
|
if (DEBUG) printf("Term Evaluated to %d\n", result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Evaluate Operand */
|
||||||
|
int evlopd(int maxsiz) {
|
||||||
|
int result = 0;
|
||||||
|
int hilo = 0; //Return LSB (1) or MSB (2)
|
||||||
|
int prns; //Optional Parenthesis after Hi/Low Operator
|
||||||
|
if (DEBUG) puts("Evaluating Operand");
|
||||||
|
skpspc();
|
||||||
|
if (cpychr('<')) hilo = 1;
|
||||||
|
else if (cpychr('>')) hilo = 2;
|
||||||
|
if (hilo) prns = cpychr('(');
|
||||||
|
result = evltrm();
|
||||||
|
if (result >= 0)
|
||||||
|
while (cpychr('+')) {
|
||||||
|
int opdval = evltrm();
|
||||||
|
if (opdval < 0) break;
|
||||||
|
result += opdval;
|
||||||
|
}
|
||||||
|
if (hilo) {
|
||||||
|
if (result < 0) xerror("Hi/Low Operator Requires Operand", "");
|
||||||
|
if (prns) cpychr(')'); //
|
||||||
|
switch (hilo) {
|
||||||
|
case 1: result = result & 0xFF; break; //LSB
|
||||||
|
case 2: result = result >> 8; break; //MSB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DEBUG) printf("Operand Evaluated to %d\n", result);
|
||||||
|
if (result > maxsiz) xerror("Operand Value too Large\n", "");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write Byte to Output File */
|
||||||
|
void outbyt(int b) {
|
||||||
|
if (curadr > -1) curadr++;
|
||||||
|
if (passno != 2) return;
|
||||||
|
fputc(b & 0xFF, outfil);
|
||||||
|
sprintf(bytstr, "%02X ", b);
|
||||||
|
strcat(mcode, bytstr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write Word to Output File */
|
||||||
|
void outwrd(int w) {
|
||||||
|
outbyt(w & 0xff);
|
||||||
|
outbyt(w >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble BYTE Pseudo-Op */
|
||||||
|
void asmbyt(void) {
|
||||||
|
do {
|
||||||
|
if (cpychr('"')) { //String Operand
|
||||||
|
while (!cpychr('"')) {outbyt(*linptr); cpychr(0); }
|
||||||
|
skpspc();
|
||||||
|
} else
|
||||||
|
outbyt(evlopd(0xFF)); //Evaluate Operand
|
||||||
|
} while (cpychr(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble WORD Pseudo-Op */
|
||||||
|
void asmwrd(void) {
|
||||||
|
do {
|
||||||
|
outwrd(evlopd(0xFFFF)); //Evaluate Operand
|
||||||
|
} while (cpychr(','));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble EQU Pseudo-Op */
|
||||||
|
void asmequ(void) {
|
||||||
|
if (label[0] == 0) xerror("EQUate without Label", 0);
|
||||||
|
setsym(evlopd(0xFFFF), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble ORG Pseudo-Op */
|
||||||
|
void asmorg(void) {
|
||||||
|
orgadr = evlopd(0xFFFF);
|
||||||
|
curadr = orgadr;
|
||||||
|
lstadr = orgadr;
|
||||||
|
if (passno == 1 && symbol.name[0]) {
|
||||||
|
symbol.value = orgadr;
|
||||||
|
symbol.bytes = 2;
|
||||||
|
}
|
||||||
|
if (passno == 2 && objtyp == PRGFIL)
|
||||||
|
outwrd(orgadr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble PROCESSOR Pseudo-Op */
|
||||||
|
void asmprc(void) {
|
||||||
|
skpspc();
|
||||||
|
while (isalnum(*linptr)) cpychr(0);
|
||||||
|
if (DEBUG) printf("Ignoring Operand %s\n", oprnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble SUBROUTINE Pseudo-Op */
|
||||||
|
void asmsub(void) {
|
||||||
|
blknum++;
|
||||||
|
sprintf(oprnd, "%d", blknum); opridx = strlen(oprnd);
|
||||||
|
if (DEBUG) printf("Block Number set to %s\n", oprnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble FILL Pseudo-Op */
|
||||||
|
void asmfll(void) {
|
||||||
|
int size = evlopd(0xFFFF);
|
||||||
|
for (int i=0; i<size; i++) {
|
||||||
|
if (passno == 2) outbyt(0);
|
||||||
|
curadr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble Pseudo-Op */
|
||||||
|
int asmpso(void) {
|
||||||
|
if (DEBUG) printf("Assembling Pseudo-Op Token '%c'\n", token);
|
||||||
|
switch (token) {
|
||||||
|
case '=': asmequ(); break; //EQU
|
||||||
|
case 'B': asmbyt(); break; //BYTE
|
||||||
|
case 'W': asmwrd(); break; //WORD
|
||||||
|
case 'F': asmfll(); break; //FILL
|
||||||
|
case 'S': asmsub(); break; //SUBROUTINE
|
||||||
|
case '*': asmorg(); break; //ORG
|
||||||
|
case 'P': asmprc(); break; //PROCESSOR
|
||||||
|
default: xerror("Undefined Pseudo-Op %s\n", mnmnc);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup Opcode */
|
||||||
|
int lkpopc(struct opc opclst[]) {
|
||||||
|
if (DEBUG) printf("Looking for OpCode %s\n", mnmnc);
|
||||||
|
char mne[4]; strncpy(mne, mnmnc, 3); //Truncate Mnemonic to Three Characters
|
||||||
|
for (int i=0; opclst[i].name[0]; i++) {
|
||||||
|
if (strcmp(opclst[i].name, mne)) continue;
|
||||||
|
token = opclst[i].token;
|
||||||
|
amode = opclst[i].amode;
|
||||||
|
if (DEBUG) printf("Found token %02X, amode %04X\n", token, amode);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for Valid Addressing Mode */
|
||||||
|
int chkmod(int mode) {
|
||||||
|
if (mode & amode) return TRUE;
|
||||||
|
xerror("Invalid Addressing Mode", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble Branch Opcode */
|
||||||
|
void asmbrn(void) {
|
||||||
|
int offset = 0;
|
||||||
|
if (DEBUG) printf("Assembling Branch Opcode Token 0x%02X\n", token);
|
||||||
|
zpage = TRUE;
|
||||||
|
if (isalpha(*linptr) || *linptr =='.') {
|
||||||
|
struct sym *target = evlsym();
|
||||||
|
if (target) offset = (target->value - curadr - 2);
|
||||||
|
}
|
||||||
|
else if (cpychr('+')) offset = evlopd(0xFF);
|
||||||
|
else if (cpychr('-')) offset = -evlopd(0xFF);
|
||||||
|
else xerror("Illegal Branch Operand\n", "");
|
||||||
|
if ((offset > 127 || offset < -128) && passno == 2)
|
||||||
|
xerror("Branch Out of Range\n", "");
|
||||||
|
if (DEBUG) printf("Branch Offset %d\n", offset);
|
||||||
|
opval = offset & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble Immediate Mode Instruction */
|
||||||
|
void asmimd(void) {
|
||||||
|
opval = evlopd(0xFF);
|
||||||
|
zpage = TRUE;
|
||||||
|
opmod = 0x08; //Immediate
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble Indirect Mode Instruction */
|
||||||
|
void asmind(void) {
|
||||||
|
if (DEBUG) puts("Assembling Indirect Mode Instruction");
|
||||||
|
zpage = TRUE; opval = evlopd(0xFFFF);
|
||||||
|
if (cpychr(',') && cpychr('X') && chkmod(INDCX)) cpychr(')'); ////(Indirect,X) opmod=0
|
||||||
|
else if (cpychr(')')) {
|
||||||
|
if (cpychr(',') && cpychr('Y') && chkmod(INDCY)) opmod = 0x10; //(Indirect),Y
|
||||||
|
else if (chkmod(INDCT)) opmod = 0x11; //(Indirect)
|
||||||
|
if (token == 0x4C) zpage = FALSE; //JMP (Indirect Absolute)
|
||||||
|
}
|
||||||
|
else chkmod(0); //Illegal Addressing Mode
|
||||||
|
if (zpage && opval > 0x00FF) xerror("Operand Value too Large\n", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble Implied/Accumulator/Absolute/ZeroPage Mode Instruction */
|
||||||
|
void asmiaz(void) {
|
||||||
|
opval = evlopd(0xFFFF);
|
||||||
|
if (opval < 0) {
|
||||||
|
if (amode != IMPLD) //Implied
|
||||||
|
if (chkmod(ACMLT)) opmod = 0x08; //Accumulator
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zpage = (opval <= 0xff) ? TRUE : FALSE;
|
||||||
|
if (zpage && chkmod(ZPAGE)) opmod = 0x04; //ZeroPage
|
||||||
|
else if (chkmod(ABSLT)) opmod = 0x0C; //Absolute
|
||||||
|
if (cpychr(',')) {
|
||||||
|
if (cpychr('X')) {
|
||||||
|
if (zpage && chkmod(ZPAGX)) opmod = 0x14; //ZeroPage,X
|
||||||
|
else if (chkmod(ABSLX)) opmod = 0x1C; //Absolute,X
|
||||||
|
} else if (cpychr('Y')) {
|
||||||
|
if (zpage && (token == 0x82 || token == 0xA2))
|
||||||
|
opmod = 0x14; //ZeroPage,Y
|
||||||
|
else {zpage = FALSE; opmod = 0x18;} //Absolute,Y
|
||||||
|
} else chkmod(0); //Illegal Addressing Mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fix Opcode (if needed) */
|
||||||
|
unsigned char fixopc(void) {
|
||||||
|
if (DEBUG) printf("Fixing OpCode $%02X+$%02X\n", token, opmod);
|
||||||
|
for (int i=0; opfix[i].token; i++)
|
||||||
|
if (opfix[i].token == token && opfix[i].opmod == opmod)
|
||||||
|
return opfix[i].opcode;
|
||||||
|
return token + opmod;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assemble Opcode */
|
||||||
|
int asmopc(void) {
|
||||||
|
opmod = 0;
|
||||||
|
if (lkpopc(opclst) == FALSE) xerror("Invalid Mnemonic %s\n", mnmnc);
|
||||||
|
if (DEBUG) printf("Assembling Opcode Token 0x%02X\n", token);
|
||||||
|
if (DEBUG) printf("Addressing Mode Mask 0x%04X\n", amode);
|
||||||
|
skpspc();
|
||||||
|
if (amode == 0) return asmpso(); //Pseudo-Op
|
||||||
|
else if (amode == RELTV) asmbrn(); //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
|
||||||
|
int opcode = fixopc();
|
||||||
|
if (DEBUG) printf("Writing OpCode $%02X\n", opcode);
|
||||||
|
outbyt(opcode);
|
||||||
|
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: linptr
|
||||||
|
* Returns: Label Found (TRUE/FALSE) */
|
||||||
|
int pmnmnc(void) {
|
||||||
|
if (DEBUG) puts("Parsing Mnemonic");
|
||||||
|
int found = pword(TRUE, mnmnc);
|
||||||
|
opridx = 0; //Initialize Operand Index
|
||||||
|
if (found) asmopc();
|
||||||
|
oprnd[opridx] = 0; //Terminate Operand String
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Comment from Input Line
|
||||||
|
* Sets: cmmnt
|
||||||
|
* Updates: linptr */
|
||||||
|
void pcmmnt(void) {
|
||||||
|
skpspc();
|
||||||
|
int i = 0;
|
||||||
|
while (*linptr >= ' ') cmmnt[i++] = *linptr++;
|
||||||
|
cmmnt[i] = 0; //Terminate Comment
|
||||||
|
if (DEBUG) {if (i) printf("Comment: %s\n"); else puts("No Comment Found");}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add Label to Symbol Table */
|
||||||
|
void addsym() {
|
||||||
|
if (symbol.value<0) xerror("Origin Not Set", "");
|
||||||
|
memcpy(&symtbl[symcnt++], &symbol, sizeof(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(int pass) {
|
||||||
|
passno = pass; //Assembly Pass Number
|
||||||
|
if (DEBUG) printf("Assembling Pass %d\n", pass);
|
||||||
|
lineno = 1; //Initialize Input File Line Number
|
||||||
|
blknum = 1; //Initialize Local Block Number
|
||||||
|
orgadr = -1; //Origin Address Not Set
|
||||||
|
curadr = orgadr; //Set Current Address to Origin
|
||||||
|
rewind(inpfil); //Start at Beginning of Input File
|
||||||
|
while (!feof(inpfil)) {
|
||||||
|
linptr = fgets(inplin, MAXSTR, inpfil);
|
||||||
|
if (linptr == NULL) break;
|
||||||
|
if (DEBUG) printf("%05d %04X: %s", lineno, curadr, inplin);
|
||||||
|
lstadr = curadr; //Set List Address
|
||||||
|
mcode[0] = 0; //Clear Generated Macbine Code
|
||||||
|
plabel(); //Parse Label
|
||||||
|
pmnmnc(); //Parse Mnemonic
|
||||||
|
pcmmnt(); //Parse Comment
|
||||||
|
if (passno == 1 && 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 );
|
||||||
|
}
|
||||||
|
lineno++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print Symbol Table */
|
||||||
|
void prtsym(void) {
|
||||||
|
fprintf(lstfil, "\n%s Symbol Table\nBlock Name Size Value\n", "Global");
|
||||||
|
for (int i=0; i<symcnt; i++) {
|
||||||
|
fprintf(lstfil, "%5d %-8s %4d %5d\n", symtbl[i].block, symtbl[i].name, symtbl[i].bytes, symtbl[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Command Line Option */
|
||||||
|
int pcoptn(char *argval) {
|
||||||
|
if (argval[0] != '-') return FALSE;
|
||||||
|
char option = toupper(argval[1]);
|
||||||
|
if (DEBUG) printf(" Option '%c'\n", option);
|
||||||
|
switch(option) {
|
||||||
|
case 'P': objtyp = PRGFIL; break; //Commodore PRG File
|
||||||
|
default: xerror("Illegal Command Line Option %s\n", argval);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse Command Line Arguments */
|
||||||
|
void pcargs(int argc, char *argv[]) {
|
||||||
|
int argnum = 0;
|
||||||
|
for (int arg = 0; arg<argc; arg++) {
|
||||||
|
if (DEBUG) printf("Arg %d='%s'\n", arg, argv[arg]);
|
||||||
|
if (arg == 0) {strcpy(prgnam, argv[arg]); continue;}
|
||||||
|
if (pcoptn(argv[arg])) continue;
|
||||||
|
switch (argnum++) {
|
||||||
|
case 0: strcpy(inpnam, argv[arg]); break;
|
||||||
|
case 1: strcpy(outnam, argv[arg]); break;
|
||||||
|
case 2: strcpy(lstnam, argv[arg]); break;
|
||||||
|
default: xerror("Too Many Arguments\n", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
///if (argnum<2) usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open File with Error Checking */
|
||||||
|
FILE * opnfil(char* name, char* mode) {
|
||||||
|
if (DEBUG) printf("Opening file '%s' with mode '%s'\n", name, mode);
|
||||||
|
FILE *fp = fopen(name, mode);
|
||||||
|
if (!fp) xerror("Error Opening File '%s'\n", name);
|
||||||
|
return fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
lstnam[0] = 0; lstfil = NULL; //Default to No List File
|
||||||
|
lineno = 0; //No Line Number (yet)
|
||||||
|
objtyp = BINFIL; //Default Object File Type to Binary
|
||||||
|
pcargs(argc, argv); //Parse Command Line Arguments
|
||||||
|
inpfil = opnfil(inpnam, "r"); //Open Input File
|
||||||
|
outfil = opnfil(outnam, "wb"); //Open Output File
|
||||||
|
if (lstnam[0]) //If List File Name Specified
|
||||||
|
lstfil = opnfil(lstnam, "w"); // Open List File
|
||||||
|
asmfil(1); //Assemble Input File (First Pass)
|
||||||
|
asmfil(2); //Assemble Input File (First Pass)
|
||||||
|
if (lstfil) prtsym(); //Print Symbol Table
|
||||||
|
}
|
||||||
|
|
124
a02.h
Normal file
124
a02.h
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
/* Definitions for A02 Assembler */
|
||||||
|
|
||||||
|
#define MAXSTR 128 //Maximum String Length
|
||||||
|
#define MAXSYM 8 //Maximum Symbol Length
|
||||||
|
#define MAXGLB 1024 //Maximum Number of Global Labels
|
||||||
|
|
||||||
|
#define FALSE 0
|
||||||
|
#define TRUE -1
|
||||||
|
|
||||||
|
/* Address Mode Bit Masks */
|
||||||
|
#define ACMLT 0x0001 //Accumulator [$xA]
|
||||||
|
#define IMMDT 0x0002 //*Immediate [w/Acc]
|
||||||
|
#define ZPAGE 0x0004 //Zero Page
|
||||||
|
#define ZPAGX 0x0008 //*Zero Page,X
|
||||||
|
//#define ZPAGY 0x0010 //*Zero Page,Y [By OpCodes]
|
||||||
|
#define ABSLT 0x0020 //Absolute
|
||||||
|
#define ABSLX 0x0040 //*Absolute,X [fixops()]
|
||||||
|
#define ABSLY 0x0080 //Absolute,Y
|
||||||
|
#define IMPLD 0x0100 //*Implied [x0001]
|
||||||
|
#define INDCT 0x0200 //(Indirect)
|
||||||
|
#define INDCX 0x0400 //(Indirect,X)
|
||||||
|
#define INDCY 0x0800 //(Indirect),Y
|
||||||
|
#define RELTV 0x1000 //Relative
|
||||||
|
|
||||||
|
struct opc {char name[4], token; int amode;};
|
||||||
|
|
||||||
|
struct opc opclst[] = {
|
||||||
|
{"EQU", '=', 0},
|
||||||
|
{"BYT", 'B', 0},
|
||||||
|
{"WOR", 'W', 0},
|
||||||
|
{"FIL", 'F', 0},
|
||||||
|
{"SUB", 'S', 0},
|
||||||
|
{"ORG", '*', 0},
|
||||||
|
{"PRO", 'P', 0},
|
||||||
|
{"BRK", 0x00, 0x0100},
|
||||||
|
{"CLC", 0x18, 0x0100},
|
||||||
|
{"CLD", 0xD8, 0x0100},
|
||||||
|
{"CLI", 0x58, 0x0100},
|
||||||
|
{"CLV", 0xB8, 0x0100},
|
||||||
|
{"DEX", 0xCA, 0x0100},
|
||||||
|
{"DEY", 0x88, 0x0100},
|
||||||
|
{"INX", 0xE8, 0x0100},
|
||||||
|
{"INY", 0xC8, 0x0100},
|
||||||
|
{"NOP", 0xEA, 0x0100},
|
||||||
|
{"PHA", 0x48, 0x0100},
|
||||||
|
{"PHP", 0x08, 0x0100},
|
||||||
|
{"PHX", 0xDA, 0x0100},
|
||||||
|
{"PHY", 0x5A, 0x0100},
|
||||||
|
{"PLA", 0x68, 0x0100},
|
||||||
|
{"PLP", 0x28, 0x0100},
|
||||||
|
{"PLX", 0xFA, 0x0100},
|
||||||
|
{"PLY", 0x7A, 0x0100},
|
||||||
|
{"RTI", 0x40, 0x0100},
|
||||||
|
{"RTS", 0x60, 0x0100},
|
||||||
|
{"SEC", 0x38, 0x0100},
|
||||||
|
{"SED", 0xF8, 0x0100},
|
||||||
|
{"SEI", 0x78, 0x0100},
|
||||||
|
{"STP", 0xDB, 0x0100},
|
||||||
|
{"TAX", 0xAA, 0x0100},
|
||||||
|
{"TAY", 0xA8, 0x0100},
|
||||||
|
{"TSX", 0xBA, 0x0100},
|
||||||
|
{"TXA", 0x8A, 0x0100},
|
||||||
|
{"TXS", 0x9A, 0x0100},
|
||||||
|
{"TYA", 0x98, 0x0100},
|
||||||
|
{"WAI", 0xCB, 0x0100},
|
||||||
|
{"ADC", 0x61, 0x0EFE},
|
||||||
|
{"AND", 0x21, 0x0EFE},
|
||||||
|
{"CMP", 0xC1, 0x0EFE},
|
||||||
|
{"EOR", 0x41, 0x0EFE},
|
||||||
|
{"LDA", 0xA1, 0x0EFE},
|
||||||
|
{"ORA", 0x01, 0x0EFE},
|
||||||
|
{"SBC", 0xE1, 0x0EFE},
|
||||||
|
{"STA", 0x81, 0x0EFE},
|
||||||
|
{"ASL", 0x02, 0x007D},
|
||||||
|
{"DEC", 0xC2, 0x007D},
|
||||||
|
{"INC", 0xE2, 0x007D},
|
||||||
|
{"LSR", 0x42, 0x007D},
|
||||||
|
{"ROL", 0x22, 0x007D},
|
||||||
|
{"ROR", 0x62, 0x007D},
|
||||||
|
{"BIT", 0x20, 0x006E},
|
||||||
|
{"CPX", 0xE0, 0x0026},
|
||||||
|
{"CPY", 0xC0, 0x0026},
|
||||||
|
{"LDY", 0xA0, 0x006E},
|
||||||
|
{"BIT", 0x20, 0x006C},
|
||||||
|
{"STY", 0x80, 0x002C},
|
||||||
|
{"STZ", 0x60, 0x006C},
|
||||||
|
{"TRB", 0x10, 0x0024},
|
||||||
|
{"TSB", 0x00, 0x0024},
|
||||||
|
{"LDX", 0xA2, 0x00A6},
|
||||||
|
{"STX", 0x82, 0x00A6},
|
||||||
|
{"JMP", 0x4C, 0x0620},
|
||||||
|
{"JSR", 0x14, 0x0020},
|
||||||
|
{"BCC", 0x90, 0x1000},
|
||||||
|
{"BCS", 0xB0, 0x1000},
|
||||||
|
{"BEQ", 0xF0, 0x1000},
|
||||||
|
{"BMI", 0x30, 0x1000},
|
||||||
|
{"BNE", 0xD0, 0x1000},
|
||||||
|
{"BPL", 0x10, 0x1000},
|
||||||
|
{"BRA", 0x80, 0x1000},
|
||||||
|
{"BVC", 0x50, 0x1000},
|
||||||
|
{"BVS", 0x70, 0x1000},
|
||||||
|
{"", 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct opf {unsigned char token, opmod, opcode;};
|
||||||
|
|
||||||
|
struct opf opfix[] = {
|
||||||
|
{0x20, 0x08, 0x89},
|
||||||
|
{0xE0, 0x08, 0xE0},
|
||||||
|
{0xC0, 0x08, 0xC0},
|
||||||
|
{0xA0, 0x08, 0xA0},
|
||||||
|
{0xA2, 0x08, 0xA2},
|
||||||
|
{0xC2, 0x08, 0x3A},
|
||||||
|
{0xE2, 0x08, 0x1A},
|
||||||
|
{0x60, 0x0C, 0x9C},
|
||||||
|
{0x60, 0x1C, 0x9E},
|
||||||
|
{0xA2, 0x18, 0xBE},
|
||||||
|
{0x82, 0x18, 0xBC},
|
||||||
|
{0x4C, 0x0C, 0x4C},
|
||||||
|
{0x4C, 0x11, 0x6C},
|
||||||
|
{0x4C, 0x00, 0x7C},
|
||||||
|
{0,0,0}
|
||||||
|
};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user