diff --git a/.gitignore b/.gitignore index ae1d7b7..48faa14 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,7 @@ output #Deprecated Files */oldclude -*/*.zip \ No newline at end of file +*/*.zip + +#Private Directories +notes \ No newline at end of file diff --git a/Makefile b/Makefile index df189d1..a3dda15 100644 --- a/Makefile +++ b/Makefile @@ -4,5 +4,6 @@ mainfile=src/c02.c outfile=c02 c02: ${incfiles} ${mainfile} gcc ${gccopts} ${incfiles} ${mainfile} -o ${outfile} + gcc ${gccopts} a02.h a02.c -o a02 clean: - rm ${outfile} + rm ${outfile} a02 diff --git a/README.md b/README.md index 9d93967..49a0960 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ but it may not be in a working state. #pragma origin 8192 //Set start address of object code #pragma zeropage $80 //Set start address of zero page variables - /* Constants */ #define TRUE = $FF ; //Constants #define FALSE = 0 @@ -54,50 +53,63 @@ struct record {char name[8]; char index;}; //Struct Definition struct record rec; //Struct Declaration /* Variables and Array Declarations */ -char i, j; //Variables -zeropage p,q; //Variables in zeropage -const char nine = 9; //Const variable set to decimal literal -const char maxsiz = $FF; //Const variable set to hexadecimal literal -const char flag = %01010101; //Const variable set to binary literal -const char debug = #TRUE; //Const variable set to constant -char r[7]; //8 byte array 0 (decimal dimension) +char b, c, d, e, f, g, h; //8-bit Variables +int i, j; //16-bit Variables +zeropage char p, q; //8-bit Variables in Page 0 +zeropage int u, v; //16-bit Variables in Page 0 +const char nine = 9; //Const 8-bit variable set to decimal literal +const char maxsiz = $FF; //Const 8-bit variable set to hexadecimal literal +const char flag = %01010101; //Const 8-bit variable set to binary literal +const char debug = #TRUE; //Const 8-bit variable set to constant +const int k = $1234; //Const 16-bit variable set to hexadecimal literal +char r[7]; //8 byte Array (decimal dimension) aligned char m[$FF]; //256 byte array aligned to page boundary +const char n = {1,2,3}; //Const array set to literal list const char s = "string"; //Const array set to string literal -const char m = {1,2,3}; //Const array set to literal list const char t = {"one", 1); //Const array set to mixed list /* Functions Declarations */ void myfunc(); //Forward declaration of function -char myfunp(tmp1, tmp2, tmp3) { - //function code -} +char fnc(c) { /*function body */} //One 8-bit Parameter +char fnd(c,d) { /*function body */} //Two 8-bit Parameters +char fne(c,d,e) { /*function body */} //Three 8-bit Parameters +char fni(i) { /*function body */} //One 16-bit Parameter +char fnj(c,i) { /*function body */} //8-bit and 16-bit Parameters + +/* Returning from a Function */ +return c, d, e; //Return up to three 8-bit values +return c,j; //Return an 8-bit an 16-bit value +return i; //Return a 16-bit value +return; //No explicit return values /* Assignments */ hmove; s80vid; //Implicit Assignments x = 0; y = a; a = 1; //Register Assignments b = c + d - e & f | g ^ h; //Assignment and Expression -r[i] = s[j+1] & t[k-1]; //Array Indexing -d[j] = r[a] + s[x] + t[y]; //Arrays Indexed by Register -r = (i>j) ? d[i] : e[j]; //Shortcut If -a<< ;b[i]>>; x++; y--; //Post-Operations +r[f] = m[g+1] & t[h-1]; //Array Indexing +r[j] = r[a] + s[x] + t[y]; //Arrays Indexed by Register +d = (e>f) ? d[e] : e[f]; //Shortcut If +b<< ;c[d]>>; x++; y--; //Post-Operations /* Function Calls */ -i = abs(n); j = min(b,c), plot(h,v,c); //Up to Three Char Arguments -q = div(m+n,d)) - t; n = mult(e+f, z); //Expression in First Arg Only -puts("string"); fputs(fp, &line); //Passing Strings and Arrays -setdst(&dst); n = strcpy(&src); //Using Multiple String Agruments -c = getc(); setptr(*,addrhi,addrlo); //No and Skipped Arguments -row,col = scnpos(); i,j,k = get3d(); //Plural Assignments -push d,r; mult(); pop p; //Pass Arguments via Stack -iprint(); inline "Hello World"; //Pass Inline String Argument -irect(); inline 10,10,100,100; //Pass Inline Char Arguments -icpstr(); inline &dst, &src; //Pass Inline Address Arguments +b = abs(c); d = min(e,f), plot(b,c,d); //Up to Three Char Arguments +b = div(c+d,e)) - f; c = mult(d+e, f); //Expression in First Arg Only +j = swap(i); j = ishift(b, i); //Pass Int or Char with Int +puts("string"); fputs(f, &s); //Passing Strings and Arrays +setdst(&r); b = strcpy(&s); //Using Multiple String Arguments +proc(@record, &record); //Pass Length and Address of Struct +c = getc(); setptr(?,g,h); //No Args and Skipped Arguments +b,c = scnpos(); d,e,f = get3d(); //Plural Assignments +push b,c; mult(); pop p; //Pass Arguments via Stack +iprint(); inline "Hello World"; //Pass Inline String Argument +irect(); inline 10,10,100,100; //Pass Inline Char Arguments +icpstr(); inline &r, &s; //Pass Inline Address Arguments /* Control Structures */ if (c = 27) goto end; -if (n) q = div(n,d) else puts("Division by 0!"); +if (b) e = div(f,g) else puts("Division by 0!"); if (b==0 || b>10 && b<20) fprint(n,"input %d in range"); -c = 'A' ; while (c <= 'Z') { putc(c); c++; } +c = 'A' ; while (c <= 'Z') { putc(c); c++; } while() { c=rdkey; if (c=0) continue; putchr(c); if (c=13) break; } do c = rdkey(); while (c=0); do {c = getchr(); putchr(c);} while (c<>13) diff --git a/a02.c b/a02.c new file mode 100644 index 0000000..cdc9338 --- /dev/null +++ b/a02.c @@ -0,0 +1,724 @@ +/* Simple 6502 Assembler * + * for C02 Compiler * + * Uses DASM Syntax but * + * supports 65C02 Op Codes */ + +#include +#include +#include +#include +#include "a02.h" + +#define DEBUG FALSE +int debug; //Ouput Debug Info + +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[MAXLBL+1]; int bytes, value, refrd;}; +struct sym symbol; //Current Symbol +struct sym symtbl[MAXSYM]; //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 + +int opridx; //Index into Operand + +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 savlno; //Line Number (Saved) + +int passno; //Assembler Pass Number (1 or 2) +int endasm; //End Assembly Flag + +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 +char incnam[256]; //Include File Name +FILE *inpfil; //Input File Pointer +FILE *outfil; //Output File Pointer +FILE *lstfil; //List File Pointer +FILE *incfil; //Include File Pointer + +/* Print Usage Info and Exit */ +void usage(char* appnam) { + printf("Usage: %s [opts] asmfile objfile [lstfile]\n", appnam); + printf(" Opts: -p - Commodore PRG format\n"); + printf(" -d - Output Debug Info\n"); + exit(EXIT_FAILURE); +} + +/* Print Error Message and Exit */ +void xerror(char* format, char *s) { + if (lineno) fprintf(stderr, "%04d: ", lineno); + fprintf(stderr, format, s); + exit(EXIT_FAILURE); +} + +/* 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; +} + +/* 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) || *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; + symbol.refrd = FALSE; +} + +/* Add Character to Beginning of String */ +void pfxstr(char c, char* s) { + for (int i=strlen(s)+1; i; i--) + s[i] = s[i-1]; //Copy All Characters to the Right + s[0] = c; //Insert Character at Beginning +} + +/* 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; + if (strlen(label) > MAXLBL) xerror("Label %s Too Long\n", label); + strcpy(symbol.name, label); + setsym(curadr, 0); + } + if (block) pfxstr('.', label); + skpspc(); //Skip to Mnemonic, Comment, or EOL + return found; +} + +/* Copy Character to Operand and Increment */ +int cpychr(int c) { + if (c && toupper(*linptr) != c) return FALSE; + if (opridx < MAXSTR) oprnd[opridx++] = toupper(*linptr); + 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++) if (opridxrefrd = TRUE; //Symbol was Referenced + 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); + if (strlen(mcode) < 9) strcat(mcode, bytstr); +} + +/* Write Word to Output File */ +void outwrd(int w) { + outbyt(w & 0xff); + outbyt(w >> 8); +} + +/* Lookup Opcode */ +int lkpopc(struct opc opl[]) { + if (debug) printf("Looking up Mnemonic %s\n", mnmnc); + token = 0xFF; //Set Token to Invalid + char mne[5]; strncpy(mne, mnmnc, 4); mne[4] = 0; //Truncate Mnemonic to Four Characters + for (int i=0; opl[i].name[0]; i++) { + if (strcmp(opl[i].name, mne)) continue; + token = opl[i].token; + amode = opl[i].amode; + if (debug) printf("Found token %02X, amode %04X\n", token, amode); + return TRUE; + } + return FALSE; +} + +/* Assemble BYTE Pseudo-Op */ +void asmbyt(void) { + if (debug) puts("Assembling BYTE Pseudo-Op"); + do { + if (cpychr('"')) { //String Operand + while (!cpychr('"')) {outbyt(*linptr); cpychr(0); } + skpspc(); + } else + outbyt(evlopd(0xFF)); //Evaluate Operand + } while (cpychr(',')); +} + +/* Assemble HEX Pseudo-Op */ +void asmhex(void) { + if (debug) puts("Assembling HEX Pseudo-Op"); + do {outbyt(evlhex(0xFF)); } while (cpychr(',')); +} + +/* Assemble WORD Pseudo-Op */ +void asmwrd(void) { + do { + outwrd(evlopd(0xFFFF)); //Evaluate Operand + } while (cpychr(',')); +} + +/* Assemble FILL Pseudo-Op */ +void asmaln(void) { + if (debug) puts("Assembling ALIGN Pseudo-Op"); + int size = evlopd(0xFFFF); if (size < 2) return; + if (debug) printf("Aligning to %d Bytes\n", size); + int fill = size - (curadr % size); if (fill == size) return; + if (debug) printf("Filling %d Bytes\n", fill); + for (int i=0; ivalue - curadr - ofsadj); + } + else if (cpychr('+')) offset = evlopd(0xFF); + else if (cpychr('-')) offset = -evlopd(0xFF); + else { + opval = evlopd(0xFFFF); + if (opval < 0) xerror("Illegal Branch Operand\n", ""); + offset = opval - curadr - 2; + } + if (debug) printf("Calculated Branch Offset of %d\n", offset); + 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 Zero Page, Relative Opcode */ +void asmzpr(void) { + int bitno = -1; + if (debug) printf("Assembling ZeroPage (Relative) Opcode Token 0x%02X\n", token); + if (strlen(mnmnc) < 4) {opmod = evlopd(7) << 4; cpychr(','); skpspc();} //Set Modifier to Bit Position + int zpval = evlopd(0xFF); cpychr(','); skpspc();//Get ZeroPage Operand + if (zpval < 0) xerror ("Instruction %s requires Multiple Operands\n", mnmnc); + if (amode == 0x0004) {zpage = TRUE; opval = zpval;} //RMB, SMB - Zero Page Operand + else {asmbrn(FALSE); opval = opval << 8 | zpval;} //BBR, BBS - Combine Operanda +} + +/* Assemble Immediate Mode Instruction */ +void asmimd(void) { + if (debug) printf("Assembling Immediate Opcode Token 0x%02X\n", token); + 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; + } + if (debug) printf("Assembling Absolute/ZeroPage 0x%02X\n", token); + 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; +} + +/* Ouput Opcode debug Info */ +void dbgopc(void) { + printf("token=$%02X, opmod=$%02X, Address Mode: ", token, opmod); + if (amode == 0x1004) puts("ZeroPage, Relative"); + else if (amode == 0x0004) puts("ZeroPage"); + else switch (opmod) { + case 0x00: if (amode == IMPLD) puts("Implied"); else puts("(Indirect,X)"); break; + case 0x08: if (opval < 0) puts("Accumulator"); else puts("#Immediate"); break; + case 0x10: puts("(Indirect),Y"); break; + case 0x11: puts("(Indirect)"); break; + case 0x04: puts("ZeroPage"); break; + case 0x0C: puts("Absolute"); break; + case 0x14: if ((token == 0x82 || token == 0xA2)) puts("ZeroPage,Y"); + else puts("ZeroPage,X"); break; + case 0x1C: puts("Absolute,X"); break; + case 0x18: puts("Absolute,Y"); break; + default: puts("UNKOWN"); + } + if (opval < 0) puts("No Operand"); + else { + printf("Operand Value %d, ", opval); + if (zpage) puts("Zero Page"); else puts("Absolute"); + } +} + +/* Assemble Opcode */ +int asmopc(int dot) { + opmod = 0; + if (asmpso(dot)) return TRUE; //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: linptr + * Returns: Label Found (TRUE/FALSE) */ +int pmnmnc(void) { + if (debug) puts("Parsing Mnemonic"); + int dot = cpychr('.'); //Optional Dot before Pseudo-Op + int found = pword(TRUE, mnmnc); + opridx = 0; //Initialize Operand Index + if (found) asmopc(dot); + 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", cmmnt); 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)); +} + + +/* Open Include File */ +void opninc(void) { + if (debug) printf("Opening Include File %s\n", incnam); + if (lstfil) fputs("\n", lstfil); + incfil = opnfil(incnam, "r"); + savlno = lineno; + lineno = 1; +} + +/* Close Include File */ +void clsinc(void) { + if (debug) printf("Closing Include File %s\n", incnam); + if (lstfil) fputs("\n", lstfil); + fclose(incfil); + incfil = NULL; + incnam[0] = 0; + lineno = savlno; + endasm = FALSE; //Clear End Flag for Return to Maun File +} + +/* 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) { + endasm = FALSE; //Reset End Assembly Flag + 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 + if (debug) printf("Rewinding Input File\n"); + rewind(inpfil); //Start at Beginning of Input File + while (TRUE) { + if (incfil) linptr = fgets(inplin, MAXSTR, incfil); + else linptr = fgets(inplin, MAXSTR, inpfil); + if (endasm || linptr == NULL) {if (incfil) {clsinc(); continue;} else 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 ); + fflush(lstfil); //Flush Output Buffer in case of Segmentation Fault + } + lineno++; + if (incnam[0] && incfil == NULL) opninc(); //Open Include File + } +} + +/* Print Symbol Table */ +void prtsym(void) { + fprintf(lstfil, "\n%s Symbol Table\nBlock Name Size Value Rfd\n", "Global"); + for (int i=0; i= 10 - BCC PRHEXC ; - ADC #$06 ; Convert ':' to 'A'... -PRHEXC: ADC #$30 ;Convert to ASCII Character - JMP PUTCHR ;Print Hex Digit and Return + INCLUDE "../include/prbyte.a02" ;PRBYTE and PRHEX routines + \ No newline at end of file diff --git a/include/header.h02 b/include/header.h02 index 610bd31..34a6f0c 100644 --- a/include/header.h02 +++ b/include/header.h02 @@ -36,15 +36,12 @@ char rdseed; //System Seed for Pseudo-Random Number Generator //System Subroutines void delchr(); //Delete previous character char getkey(); //Read ASCII character from Console -char getpos(); //Get Cursor Position -char getsiz(); //Get Screen Size void newlin(); //Advance cursor to beginning of next line char polkey(); //Poll Console for character char putchr(); //Print ASCII character to Console void prbyte(); //Print Accumulator as Hexadadecimal number void prhex(); //Print Low Nybble of Accumulator as Hex Digit char getchr(); //Wait for character from Console -void setpos(); //Set Cursor Position //System Labels start: //Start of Code diff --git a/include/keydef.a02 b/include/keydef.a02 new file mode 100644 index 0000000..1b50623 --- /dev/null +++ b/include/keydef.a02 @@ -0,0 +1,37 @@ +;Standard ASCII Key Code Definitions +;Undefined Keys hae value $00 + +KEYBCK EQU $08 ;Backspace +KEYBRK EQU $03 ;Break +KEYCLR EQU $00 ;Clear +KEYCPY EQU $00 ;Copy [Acorn Atom] +KEYDEL EQU $7F ;Delete +KEYDN EQU $00 ;Cursor Down +KEYESC EQU $1B ;Escape +KEYFN1 EQU $00 ;F1 +KEYFN2 EQU $00 ;F2 +KEYFN3 EQU $00 ;F3 +KEYFN4 EQU $00 ;F4 +KEYFN5 EQU $00 ;F5 +KEYFN6 EQU $00 ;F6 +KEYFN7 EQU $00 ;F7 +KEYFN8 EQU $00 ;F8 +KEYFN9 EQU $00 ;F9 +KEYFNA EQU $00 ;F10 +KEYFNB EQU $00 ;F11 +KEYFNC EQU $00 ;F12 +KEYHLP EQU $00 ;Help [C128/C65] +KEYHOM EQU $00 ;Home +KEYINS EQU $00 ;Insert +KEYLFT EQU $00 ;Cursor Left +KEYLNF EQU $0A ;;Line Feed [C128] +KEYRGT EQU $00 ;Cursor Right +KEYRTN EQU $0D ;Return +KEYRTS EQU $80 ;Shift-Return +KEYRUN EQU $00 ;Run [PET/CBM] +KEYRVF EQU $92 ;Reverse OffCtrl-0 +KEYRVS EQU $12 ;Reverse On Ctrl-9 +KEYSPS EQU $00 ;Shifted Space +KEYTAB EQU $09 ;Tab +KEYTAS EQU $00 ;Shift-Tab +KEYUP EQU $00 ;Cursor Up diff --git a/include/keydef.h02 b/include/keydef.h02 new file mode 100644 index 0000000..b11e438 --- /dev/null +++ b/include/keydef.h02 @@ -0,0 +1,37 @@ +/* Standard ASCII Key Code Definitions * + * Undefined Keys hae value $00 * + +#define KEYBCK $08 //Backspace +#define KEYBRK $03 //Break +#define KEYCLR $00 //Clear +#define KEYCPY $00 //Copy +#define KEYDEL $7F //Delete +#define KEYDN $00 //Cursor Down +#define KEYESC $1B //Escape +#define KEYFN1 $00 //1 +#define KEYFN2 $00 //2 +#define KEYFN3 $00 //3 +#define KEYFN4 $00 //4 +#define KEYFN5 $00 //5 +#define KEYFN6 $00 //6 +#define KEYFN7 $00 //7 +#define KEYFN8 $00 //8 +#define KEYFN9 $00 //9 +#define KEYFNA $00 //10 +#define KEYFNB $00 //11 +#define KEYFNC $00 //12 +#define KEYHLP $00 //Help +#define KEYHOM $00 //Home +#define KEYINS $00 //Insert +#define KEYLFT $00 //Cursor Left +#define KEYLNF $0A //Line Feed +#define KEYRGT $00 //Cursor Right +#define KEYRTN $0D //Return +#define KEYRTS $80 //Shift-Return +#define KEYRUN $00 //Run +#define KEYRVF $92 //Reverse Off +#define KEYRVS $12 //Reverse On +#define KEYSPS $00 //Shifted Space +#define KEYTAB $09 //Tab +#define KEYTAS $00 //Shift-Tab +#define KEYUP $00 //Cursor Up diff --git a/include/orao/screen.a02 b/include/orao/screen.a02 new file mode 100644 index 0000000..b0ac3d5 --- /dev/null +++ b/include/orao/screen.a02 @@ -0,0 +1,39 @@ +;Screen Control Assembly Lanuage Routines for C02 +;Skeleton Code for Systems with no Screen Control + + SUBROUTINE _SCREEN + +SMTEXT EQU $00 ;Default Text Screen +SMWIDE EQU $FF ;Wide Text Screen (Undefined) + +;Set Screen Mode +SETSCR: CMP SMTEXT ;If Default Text Screen + BEQ GETSCR ;Return Return 0 + LDA #$FF ;Else Return ERROR + RTS + ;Else Return 0 +;Get Screen Mode +GETSCR: LDA #0 ;Return 0 (Default Text Mode) + RTS + +;Clear the Screen +CLRSCR: LDA #$0C ;Print Form Feed + JMP PUTCHR ;and Return + +;Move Cursor Home +CRSRHM EQU $E395 ;Aliad to HOME Routine + +;Move Cursor to Specified Coordinates +SETPOS: STA $E9 ;Set CURCOL + STY $E8 ;Set CURROW + JMP $E39D ;Set Pointers and Return + +;Get Cursor Position +GETPOS: LDA $E9 ;Load Column Position + LDY $E8 ;Load Row Position + RTS ;Return Cursor Column in A, Row in Y + +;Get Screen Size +GETSIZ: LDA #32 ;Return 32 Columns + TAY ;and 32 Rows + RTS diff --git a/include/orao/screen.h02 b/include/orao/screen.h02 new file mode 100644 index 0000000..df50301 --- /dev/null +++ b/include/orao/screen.h02 @@ -0,0 +1,38 @@ +/********************************************* + * Screen Control Routines for Orao Computer * + *********************************************/ + +/* Screen Modes for getscr() and setscr() */ +#define SMTEXT $00 //System Default Text Mode +#define SMWIDE $FF //Wide Screen Text Mode (Unsupported) + +/* Clear the Screen */ +void clrscn(); + +/* Move Cursor to Top Left of Screen */ +void crsrhm(); + +/* Get Current Cursor Position * + * Returns: cursor column * + * cursor row */ +char getpos(); + +/* Get Screen Mode * + * Returns: char mode - Current Screen Mode */ +char getscr(); + +/* Get Screen Size * + * Returns: width in columns * + * height in rows */ +char getsiz(); + +/* Move Cursor to Specified Position * + * Args: column - screen column (0 = left) * + * row - screen line (0 = top) */ +void setpos(); + +/* Set Screen Mode * + * Args: char mode - screen mode * + * 0 = default text mode * + * Returns: $FF if Mode Invalid */ +char setscr(); diff --git a/include/oric/screen.a02 b/include/oric/screen.a02 index 4f2272c..5a0e71e 100644 --- a/include/oric/screen.a02 +++ b/include/oric/screen.a02 @@ -1,5 +1,20 @@ ;Screen Control Assembly Lanuage Routines for Oric-1 + SUBROUTINE _SCREEN + +SMTEXT EQU $00 ;Default Text Screen +SMWIDE EQU $FF ;Wide Text Screen (Undefined) + +;Set Screen Mode +SETSCR: CMP SMTEXT ;If Default Text Screen + BEQ GETSCR ;Return Return 0 + LDA #$FF ;Else Return ERROR + RTS + ;Else Return 0 +;Get Screen Mode +GETSCR: LDA #0 ;Return 0 (Default Text Mode) + RTS + ;Clear the Screen CLRSCR EQU $CC0A ;Basic CLS Routine (Atmos = $CCCE) diff --git a/include/oric/screen.h02 b/include/oric/screen.h02 index 3b8b6b0..a4b81e6 100644 --- a/include/oric/screen.h02 +++ b/include/oric/screen.h02 @@ -2,6 +2,10 @@ * Screen Control Functions for Oric-1 * ***************************************/ +/* Screen Modes for getscr() and setscr() */ +#define SMTEXT $00 //System Default Text Mode +#define SMWIDE $FF //Wide Screen Text Mode (Unsupported) + /* Clear the Screen */ void clrscn(); @@ -13,6 +17,10 @@ void crsrhm(); ( cursor row */ char getpos(); +/* Get Screen Mode * + * Returns: char mode - Current Screen Mode */ +char getscr(); + /* Get Screen Size * * Returns: width in columns * * height in rows */ @@ -22,3 +30,9 @@ char getsiz(); * Args: column - screen column (0 = left) * * row - screen line (0 = top) */ void setpos(); + +/* Set Screen Mode * + * Args: char mode - screen mode * + * 0 = default text mode * + * Returns: $FF if Mode Invalid */ +char setscr(); diff --git a/include/py65.h02 b/include/py65.h02 index 2c0fdf2..3fd9005 100644 --- a/include/py65.h02 +++ b/include/py65.h02 @@ -23,7 +23,7 @@ char temp0, temp1, temp2, temp3; //Temporary Storage //Memory Mapped I/O char putcon; //Write Character to Console -char getcomn; //Read Character from Console +char getcon; //Read Character from Console //System Subroutines char polkey(); //Poll Console for character diff --git a/include/screen.a02 b/include/screen.a02 index 47d791f..f025045 100644 --- a/include/screen.a02 +++ b/include/screen.a02 @@ -1,6 +1,19 @@ ;Screen Control Assembly Lanuage Routines for C02 ;Skeleton Code for Systems with no Screen Control + SUBROUTINE _SCREEN + +SMTEXT EQU $00 ;Default Text Screen +SMWIDE EQU $FF ;Wide Text Screen (Undefined) + +;Set Screen Mode +SETSCR: CMP SMTEXT ;If Not Default Text + BEQ GETPOS ;Return Error + ;Else Return 0 +;Get Screen Mode +GETSCR: LDA #0 ;Return 0 (Default Text Mode) + RTS + ;Clear the Screen CLRSCR: RTS ;No Action @@ -17,3 +30,4 @@ GETPOS: LDA #$FF ;Return Error ;Get Screen Size GETSIZ EQU GETPOS ;Return Error + diff --git a/include/screen.h02 b/include/screen.h02 index dbe2649..265f78d 100644 --- a/include/screen.h02 +++ b/include/screen.h02 @@ -1,6 +1,11 @@ -/******************************************** - * screen - Screen Control Routines for C02 * - ********************************************/ +/*********************************** + * Screen Control Routines for C02 * + ***********************************/ + +/* Screen Modes for getscr() and setscr() * + * Invalid Modes have value $FF */ +#define SMTEXT $00 //System Default Text Mode +#define SMWIDE $FF //Wide Screen Text Mode (Usuallu 80 Columns) /* Clear the Screen */ void clrscn(); @@ -18,7 +23,17 @@ char getpos(); * height in rows */ char getsiz(); -/* Move Cursor to Specified Position * - * Args: column - screen column (0 = left) * - * row - screen line (0 = top) */ +/* Get Screen Mode * + * Returns: char mode - Current Screen Mode */ +char getscr(); + +/* Move Cursor to Specified Position * + * Args: char col - screen column (0 = left) * + * char row - screen line (0 = top) */ void setpos(); + +/* Set Screen Mode * + * Args: char mode - screen mode * + * 0 = default text mode * + * Returns: $FF if Mode Invalid */ +char setscr(); diff --git a/include/stdlib.a02 b/include/stdlib.a02 index 85f61f8..388ca1f 100644 --- a/include/stdlib.a02 +++ b/include/stdlib.a02 @@ -3,15 +3,17 @@ ; external zero page locations SRCLO and SRCHI ; and external locations RANDOM, RDSEED, TEMP0, TEMP1, and TEMP2. + SUBROUTINE STDLIB + ;abs(n) - Get ABSolute Value ;Args: A = Number to get Absolute Value Of ;Affects: C, N, Z ;Returns: A = Absolute Value of Argument ABS: CMP #$80 ;If Negative (High Bit Set) - BCC ABSX ; Carry will Already be Set + BCC .ABSX ; Carry will Already be Set EOR #$FF ; One's Complement ADC #$00 ; and Increment (Carry set by CMP) -ABSX: RTS +.ABSX RTS ;max(m,n) - Get MAXimum of Two Numbers ;Args: A,Y = Numbers to Compare @@ -20,9 +22,9 @@ ABSX: RTS ;Returns: A = Larger of the Two Arguments MAX: STY TEMP0 ;Save Second Parameter CMP TEMP0 ;If First Parameter - BCC MAXX ; Greater than Second Parameter + BCC .MAXX ; Greater than Second Parameter TYA ;Copy Second Parameter into Accumulator -MAXX: RTS +.MAXX RTS ;min(m,n) - Get MINimum Get MAXimum of Two Numbers ;Args: A,Y = Numbers to Compare @@ -31,9 +33,9 @@ MAXX: RTS ;Returns: A = Smaller of the Two Arguments MIN: STY TEMP0 ;Save Second Parameter CMP TEMP0 ;If First Parameter - BCS MINX ; Less than Second Parameter + BCS .MINX ; Less than Second Parameter TYA ;Copy Second Parameter into Accumulator -MINX: RTS +.MINX RTS ;mult(m,n) - MULTiply Two Numbers ;Args: A = Multiplicand @@ -48,13 +50,13 @@ MULT: STA TEMP0 ;Store Multiplicand STY TEMP1 ;Store Multiplier ;Multiply TEMP0 times TEMP1 MULTT: LDA #$00 ;Initialize Accumulator - BEQ MULTE ;Enter Loop -MULTA: CLC + BEQ .MULTE ;Enter Loop +.MULTA CLC ADC TEMP0 ;Add Multiplicand -MULTL: ASL TEMP0 ;Shift Multiplicand Left -MULTE: LSR TEMP1 ;Shift Multiplier Right - BCS MULTA ;If Bit Shifted Out, Add Multiplicand - BNE MULTL ;Loop if Any 1 Bits Left +.MULTL ASL TEMP0 ;Shift Multiplicand Left +.MULTE LSR TEMP1 ;Shift Multiplier Right + BCS .MULTA ;If Bit Shifted Out, Add Multiplicand + BNE .MULTL ;Loop if Any 1 Bits Left LDY TEMP2 ;Load Y with MSB TAX ;and Copy LSB to X RTS @@ -73,13 +75,13 @@ DIV: STA TEMP0 ;Store Dividend DIVT: LDA #$00 ;Clear Accumulator LDX #$07 ;Load Loop Counter CLC -DIVL: ROL TEMP0 ;Shift Bit Out of Dividend +.DIVL ROL TEMP0 ;Shift Bit Out of Dividend ROL ; into Accumulator CMP TEMP1 ;If Accumulator - BCC DIVS ; >= Divisor + BCC .DIVS ; >= Divisor SBC TEMP1 ;Subtract Divisor -DIVS: DEX ;Decrement Counter - BPL DIVL ; and Loop +.DIVS DEX ;Decrement Counter + BPL .DIVL ; and Loop ROL TEMP0 ;Shift Result into Dividend TAY ;Copy Remainder to Y Register LDA TEMP0 ;Load Result into Accumulator @@ -90,9 +92,9 @@ DIVS: DEX ;Decrement Counter ;Affects A,N,Z,C RAND: LDA RANDOM ;Load Last Result ASL ;Shift the Seed - BCC RANDX ;If a one was shifted out + BCC .RANDX ;If a one was shifted out EOR #$1D ; Twiddle the bite -RANDX: STA RANDOM ;Save the Seed +.RANDX STA RANDOM ;Save the Seed RTS ;Seed Pseudo-Random Number Generator @@ -100,25 +102,71 @@ RANDX: STA RANDOM ;Save the Seed ;Affects A,N,Z,C ;Sets RANDOM RANDS: ORA #$00 ;If Passed Value not 0 - BNE RANDX ; Store in Seed and Return + BNE .RANDX ; Store in Seed and Return LDA RDSEED ;Load System Generated Seed - BNE RANDX ;If Not 0, Store and Return + BNE .RANDX ;If Not 0, Store and Return ADC #$01 ;Else Add 1 or 2 - BNE RANDX ; then Store and Return + BNE .RANDX ; then Store and Return -;Return A Shifted Y Bytes to the Left -;Affects A,Y,N,Z,C -;Affects A,Y,N,Z,C -SHIFTL: ASL ;Shift Byte to Left - DEY ;Decrement Counter - BNE SHIFTL ; and Loop if Not 0 +;swap(byte) - Swap Low and High Nybbles in Byte +;Args: A = Byte to Swap +;Affects Y,N,Z,C +;Returns: A = Swapped Byte +SWAP: LDY #4 ;Set Count to 4 and Rotate Left + +;rotatl(byte,count) - Rotate byte by count Bits to the Left +;Args = Byte to Rotate +;Y = Number of Bits to Rotate +;Affects X,Y,N,Z,C +;Returns: A = Rotated Byte +ROTATL: INY ;Pre-Increment Counter +.ROTALL DEY ;Decrement Counter + BEQ .ROTATX ;If Not Zero + ASL ; Shift Left One Bit + ADC #0 ; Copy Carry into Bit 0 + BNE .ROTALL ; If Not Zero, Loop +.ROTATX RTS + +;rotatr(byte,count) - Shift byte by count Bits to the Right +;Args = Byte to Rotate +;Y = Number of Bits to Rotate +;Affects Y,N,Z,C +;Returns: A = Rotated Byte +ROTATR: INY ;Pre-Increment Counter +.ROTALR DEY ;Decrement Counter + BEQ .ROTATX ;If Not Zero + LSR ; Shift Right One Bit + BCC .ROTATS ; If Carry Set + ORA #$80 ; Copy Carry into Bit 7 +.ROTATS BNE .ROTALR ; If Not Zero, Loop RTS -;Return A Shifted Y Bytes to the Right -;Affects A,Y,N,Z,C -SHIFTR: LSR ;Shift Byte to Right - DEY ;Decrement Counter - BNE SHIFTR ; and Loop if Not 0 +SHFTL4: LDY #4; ;Set Count to 4 and Shift Left + +;shiftl(byte,count) - Shift byte by Count bits to the Left +;Args = Byte to Shift +;Y = Number of Bits to Rotate +;Affects Y,N,Z,C +;Returns: A = Shifted Byte +SHIFTL: INY ;Pre-Increment Counter +.SHIFLL DEY ;Decrement Counter + BEQ .SHIFTX ;If Not Zero + ASL ; Shift Byte to Left + BNE .SHIFLL ; and Loop if Not 0 +.SHIFTX RTS + +SHFTR4: LDY #4; ;Set Count to 4 and Shift Right + +;shiftr(byte,count) - Shift byte by Count bits to the Right +;Args = Byte to Shift +;Y = Number of Bits to Rotate +;Affects Y,N,Z,C +;Returns: A = Shifted Byte +SHIFTR: INY ;Pre-Increment Counter +.SHIFLR DEY ;Decrement Counter + BEQ .SHIFTX ;If Not Zero + LSR ; Shift Byte to Right + BNE .SHIFLR ; and Loop if Not 0 RTS ;atoc(&s) - ASCII string TO Character @@ -130,11 +178,11 @@ SHIFTR: LSR ;Shift Byte to Right ; Y = Number of Digits ATOC: JSR SETSRC ;Initialize Source String STY TEMP0 ;Initialize Result -ATOCL: LDA (SRCLO),Y ;Get Next Character +.ATOCL LDA (SRCLO),Y ;Get Next Character CMP #$30 ;If Less Than '0' - BCC ATOCX ; Exit + BCC .ATOCX ; Exit CMP #$3A ;If Greater Than '9' - BCS ATOCX ; Exit + BCS .ATOCX ; Exit AND #$0F ;Convert to Binary Nybble STA TEMP1 ; and Save It LDA TEMP0 ;Load Result @@ -145,8 +193,8 @@ ATOCL: LDA (SRCLO),Y ;Get Next Character ADC TEMP1 ;Add Saved Nybble STA TEMP0 ; and Store Result INY ;Increment Index - BPL ATOCL ; and Loop -ATOCX: LDA TEMP0 ;Load Result + BPL .ATOCL ; and Loop +.ATOCX LDA TEMP0 ;Load Result RTS ;And Return ;ctoa(n) - Character TO ASCII string @@ -161,19 +209,19 @@ CTOA: JSR SETDST ;Initialize Source String LDY #0 ;Initialize Index into String JSR CUBCD ;Convert Accumulator to Unpacked BCD LDA TEMP2 ;Get MSB - BEQ CTOA1 ;If Not Zero - JSR CTOAN ; Convert Low Nybble -CTOA1: LDA TEMP1 ;Get Low Byte - BNE CTOA2 ;If Not Zero + BEQ .CTOA1 ;If Not Zero + JSR .CTOAN ; Convert Low Nybble +.CTOA1 LDA TEMP1 ;Get Low Byte + BNE .CTOA2 ;If Not Zero CMP TEMP2 ; and Hundreds - BEQ CTOA3 ; not Zero -CTOA2: JSR CTOAN ; Convert It -CTOA3: LDA TEMP0 ;Get Low Byte - JSR CTOAN ;and Convert Low Nybble + BEQ .CTOA3 ; not Zero +.CTOA2 JSR .CTOAN ; Convert It +.CTOA3 LDA TEMP0 ;Get Low Byte + JSR .CTOAN ;and Convert Low Nybble LDA #$00 - BEQ CTOAX ;Terminate String -CTOAN: ORA #$30 ;Convert to ASCII digit -CTOAX: STA (DSTLO),Y ;Store in String + BEQ .CTOAX ;Terminate String +.CTOAN ORA #$30 ;Convert to ASCII digit +.CTOAX STA (DSTLO),Y ;Store in String INY ;and Increment Offset TYA ;Copy String Length to Accumulator RTS @@ -207,23 +255,22 @@ UPBCD: LDA TEMP1 ;Get Low Byte ; TEMP2 = Hundreds Digit ;Returns: A = Hundreds Digit ; X = 0 -CVBCD: STA TEMP0 ;Save Binary Value -CVBCDT: LDA #0 ;Clear BCD Bytes - STA TEMP1 - STA TEMP2 - LDX #8 ;Process 8 bits of Binary - PHP ;Save Status Register - SEI ;Disable Interupts - SED ;Set Decimal Mode -CVBCDL: ASL TEMP0 ;Shift High Bit into Carry - LDA TEMP1 ;Add BCD Low Byte to Itself - ADC TEMP1 ; Plus Bit Shifted out of Binary - STA TEMP1 ; Effectively Multiplying It by 2 - LDA TEMP2 ;Add BCD MSB to Itself - ADC TEMP2 ; Plus Bit Shifted out of Low Byte - STA TEMP2 ; Effectively Multiplying It by 2 - DEX ;Decrement Counter and - BNE CVBCDL ; Process Next Bit - PLP ;Restore Status Register +CVBCD: STA TEMP0 ;Save Binary Value +CVBCDT: LDA #0 ;Clear BCD Bytes + STA TEMP1 + STA TEMP2 + LDX #8 ;Process 8 bits of Binary + PHP ;Save Status Register + SEI ;Disable Interupts + SED ;Set Decimal Mode +.CVBCDL ASL TEMP0 ;Shift High Bit into Carry + LDA TEMP1 ;Add BCD Low Byte to Itself + ADC TEMP1 ; Plus Bit Shifted out of Binary + STA TEMP1 ; Effectively Multiplying It by 2 + LDA TEMP2 ;Add BCD MSB to Itself + ADC TEMP2 ; Plus Bit Shifted out of Low Byte + STA TEMP2 ; Effectively Multiplying It by 2 + DEX ;Decrement Counter and + BNE .CVBCDL ; Process Next Bit + PLP ;Restore Status Register RTS - diff --git a/include/template.h02 b/include/template.h02 index 2395599..f49e83d 100644 --- a/include/template.h02 +++ b/include/template.h02 @@ -1,6 +1,6 @@ -/************************************************ - * template - Template Library Routines for C02 * - ************************************************/ +/*************************************************** + * template.a02 - Template Module Routines for C02 * + ***************************************************/ /* Function Description * * Args: a - First Argument * diff --git a/include/via.h02 b/include/via.h02 new file mode 100644 index 0000000..907baa2 --- /dev/null +++ b/include/via.h02 @@ -0,0 +1,20 @@ +/* MOS 6522 VIA Registers */ + +struct via { + char iorb; //Input/Output Register B + char iora; //Input/Output Register A + char ddrb; //Data Direction Register B + char ddra; // Data Direction Register A + char t1cl; //T1 Low-Order Counter + char t1ch; //T1 High-Order Counter + char t1ll; //T1L-L | T1 Low-Order Latches + char t1lh; //T1 High-Order Latches + char t2cl; //T2 Low-Order Latches + char t2ch; //T2 High-Order Counter + char sr; //Shift Register + char acr; //Auxiliary Control Register + char pcr; //Peripheral Control Register + char ifr; //Interrupt Flag Register + char ier; //Interrupt Enable Register + char nhra; //Input/Output Register A (No Handshake) +} diff --git a/include/vic.a02 b/include/vic.a02 index afcb612..ca60c9e 100644 --- a/include/vic.a02 +++ b/include/vic.a02 @@ -100,4 +100,6 @@ NEWLIN: LDX #0 ;Store 0 STX $D3 ;in Cursor Column and JMP $E8C3 ;Execute NXTLINE Routine - INCLUDE "../include/prbyte.a02" ;PRBYTE and PRHEX routines \ No newline at end of file +;Print Zero-Terminated String +PUTSTR: TXA ;Copy LSB to Accumulator + JMP $CB1E ;Execute STROUT Routine diff --git a/include/vic/keydef.a02 b/include/vic/keydef.a02 new file mode 100644 index 0000000..b868a1f --- /dev/null +++ b/include/vic/keydef.a02 @@ -0,0 +1,37 @@ +;PETSCII Key Code Definitions +;for Commmodore 64 Computer + +KEYBCK EQU $00 ;Backspace [N/A] +KEYBRK EQU $03 ;Break (RUN/STOP) +KEYCLR EQU $93 ;Clear (Shift-CLR/HOME) +KEYCPY EQU $00 ;Copy [N/A] +KEYDEL EQU $14 ;Delete +KEYDN EQU $11 ;Cursor Down +KEYESC EQU $00 ;Escape [N/A] +KEYFN1 EQU $85 ;F1 (F1/F2) +KEYFN2 EQU $89 ;F2 (Shift-F1/F2) +KEYFN3 EQU $86 ;F3 (F3/F4) +KEYFN4 EQU $8A ;F4 (Shift-F3/F4) +KEYFN5 EQU $87 ;F5 (F5/F6) +KEYFN6 EQU $8B ;F6 (Shift-F5/F6) +KEYFN7 EQU $88 ;F7 (F7/F8) +KEYFN8 EQU $8C ;F8 (Shift-F7/F8) +KEYFN9 EQU $00 ;F9 [N/A] +KEYFNA EQU $00 ;F10 [N/A] +KEYFNB EQU $00 ;F11 [N/A] +KEYFNC EQU $00 ;F12 [N/A] +KEYHLP EQU $84 ;Help [N/A] +KEYHOM EQU $13 ;Home (CLR/HOME) +KEYINS EQU $94 ;Insert (Shift-INS/DEL) +KEYLFT EQU $9D ;Cursor Left +KEYLNF EQU $00 ;Line Feed [N/A] +KEYRGT EQU $1D ;Cursor Right +KEYRTN EQU $0D ;Return +KEYRTS EQU $8D ;Shift-Return +KEYRUN EQU $00 ;Run (Shift-RUN/STOP) +KEYRVF EQU $92 ;Reverse Off +KEYRVS EQU $12 ;Reverse On +KEYSPS EQU $A0 ;Shifted Space +KEYTAB EQU $09 ;Tab +KEYTAS EQU $00 ;Shift-Tab [N/A] +KEYUP EQU $91 ;Cursor Up diff --git a/include/vic/keydef.h02 b/include/vic/keydef.h02 new file mode 100644 index 0000000..ab29a51 --- /dev/null +++ b/include/vic/keydef.h02 @@ -0,0 +1,37 @@ +/* PETSCII Key Code Definitions * + * for Commodore 64 Computer */ + +#define KEYBCK $00 //Backspace +#define KEYBRK $03 //Break (RUN/STOP) +#define KEYCLR $93 //Clear (Shift-CLR/HOME) +#define KEYCPY $00 //Copy [N/A] +#define KEYDEL $14 //Delete +#define KEYDN $11 //Cursor Down +#define KEYESC $00 //Escape [N/A] +#define KEYFN1 $85 //Function Key 1 (F1/F2) +#define KEYFN2 $89 //Function Key 2 (Shift-F1/F2) +#define KEYFN3 $86 //Function Key 3 (F3/F4) +#define KEYFN4 $8A //Function Key 4 (Shift-F3/F4) +#define KEYFN5 $87 //Function Key 5 (F5/F6) +#define KEYFN6 $8B //Function Key 6 (Shift-F5/F6) +#define KEYFN7 $88 //Function Key 7 (F7/F8) +#define KEYFN8 $8C //Function Key 8 (Shift-F7/F8) [HELP on C16] +#define KEYFN9 $00 //Function Key 9 [N/A] +#define KEYFNA $00 //Function Key 10 [N/A] +#define KEYFNB $00 //Function Key 11 [N/A] +#define KEYFNC $00 //Function Key 12 [N/A] +#define KEYHLP $84 //Help [N/A] +#define KEYHOM $13 //Home (CLR/HOME) +#define KEYINS $94 //Insert (Shift-INS/DEL) +#define KEYLFT $9D //Cursor Left +#define KEYLNF $00 //Line Feed (N/A) +#define KEYRGT $1D //Cursor Right +#define KEYRTN $0D //Return +#define KEYRTS $8D //Shift-Return +#define KEYRUN $00 //Run (Shift-RUN/STOP) +#define KEYRVF $92 //Reverse Off +#define KEYRVS $12 //Reverse On +#define KEYSPS $A0 //Shifted Space +#define KEYTAB $09 //Tab +#define KEYTAS $00 //Shift-Tab [N/A] +#define KEYUP $91 //Cursor Up diff --git a/include/vic/screen.a02 b/include/vic/screen.a02 index 7e16bde..f262a18 100644 --- a/include/vic/screen.a02 +++ b/include/vic/screen.a02 @@ -1,5 +1,20 @@ ;Screen Control Assembly Lanuage Routines for VIC-20 + SUBROUTINE _SCREEN + +SMTEXT EQU $00 ;Default Text Screen +SMWIDE EQU $FF ;Wide Text Screen (Undefined) + +;Set Screen Mode +SETSCR: CMP SMTEXT ;If Default Text Screen + BEQ GETSCR ;Return Return 0 + LDA #$FF ;Else Return ERROR + RTS + ;Else Return 0 +;Get Screen Mode +GETSCR: LDA #0 ;Return 0 (Default Text Mode) + RTS + ;Clear the Screen CLRSCR EQU $E55F ;Aliased to CLSR Routine diff --git a/include/vic/screen.h02 b/include/vic/screen.h02 index 595c261..f45edd6 100644 --- a/include/vic/screen.h02 +++ b/include/vic/screen.h02 @@ -2,6 +2,10 @@ * Screen Control Functions for VIC-20 * ***************************************/ +/* Screen Modes for getscr() and setscr() */ +#define SMTEXT $00 //System Default Text Mode +#define SMWIDE $FF //Wide Screen Text Mode (Unsupported) + /* Clear the Screen */ void clrscn(); @@ -13,6 +17,10 @@ void crsrhm(); ( cursor row */ char getpos(); +/* Get Screen Mode * + * Returns: char mode - Current Screen Mode */ +char getscr(); + /* Get Screen Size * * Returns: width in columns * * height in rows */ @@ -22,3 +30,9 @@ char getsiz(); * Args: column - screen column (0 = left) * * row - screen line (0 = top) */ void setpos(); + +/* Set Screen Mode * + * Args: char mode - screen mode * + * 0 = default text mode * + * Returns: $FF if Mode Invalid */ +char setscr(); diff --git a/include/vic20.a02 b/include/vic20.a02 index 475b44b..c3c8634 100644 --- a/include/vic20.a02 +++ b/include/vic20.a02 @@ -16,3 +16,4 @@ BASIC: DC $0C, $10 ;Pointer to Next Line DC $00, $00 ;End of Basic Program INCLUDE "../include/vic.a02" ;Include VIC 20 Common Code + INCLUDE "../include/prbyte.a02" ;PRBYTE and PRHEX routines \ No newline at end of file diff --git a/include/vic3k.a02 b/include/vic3k.a02 index 90db978..9225491 100644 --- a/include/vic3k.a02 +++ b/include/vic3k.a02 @@ -16,3 +16,4 @@ BASIC: DC $0C, $04 ;Pointer to Next Line DC $00, $00 ;End of Basic Program INCLUDE "../include/vic.a02" ;Include VIC 20 Common Code + INCLUDE "../include/prbyte.a02" ;PRBYTE and PRHEX routines \ No newline at end of file diff --git a/include/vic8k.a02 b/include/vic8k.a02 index 0b11ee3..fc4db85 100644 --- a/include/vic8k.a02 +++ b/include/vic8k.a02 @@ -16,3 +16,4 @@ BASIC: DC $0C, $12 ;Pointer to Next Line DC $00, $00 ;End of Basic Program INCLUDE "../include/vic.a02" ;Include VIC 20 Common Code + INCLUDE "../include/prbyte.a02" ;PRBYTE and PRHEX routines \ No newline at end of file diff --git a/src/c02.c b/src/c02.c index a73658f..2a69a2f 100644 --- a/src/c02.c +++ b/src/c02.c @@ -1,227 +1,228 @@ -/************************************************************** - * C02 Compiler - (C) 2013 Curtis F Kaylor * - * * - * C02 is a simpified C-like language designed for the 6502 * - * * - * This Compiler generates crasm compatible assembly language * - * * - **************************************************************/ - -#include -#include -#include -#include -#include - -#include "common.h" //Common Code used by all Modules -#include "files.h" //Open and Close Files -#include "asm.h" //Write out Assembly Language -#include "parse.h" //General Code Parsing -#include "vars.h" //Variable Parsing, Lookup, and Allocation -#include "expr.h" //Expression Parsing -#include "label.h" //Label Parsing, Generation, and Lookup -#include "cond.h" //Conditional Parsing -#include "stmnt.h" //Statement Compiling Code -#include "dclrtn.h" //Statement Compiling Code -#include "include.h" //Include File Parsing - -/* Initilize Compiler Variables */ -void init(void) { - initim(); //Initialize Elapsed Time - DEBUG("Initializing Compiler Variables\n",0) - concnt = 0; //Number of Constants Defined - varcnt = 0; //Number of Variables in Table - lblcnt = 0; //Number of Labels in stack - padcnt = 0; //Number of Padding Bytes at End - curcol = 0; //Current Column in Source Code - curlin = 0; //Current Line in Source Code - alcvar = TRUE; //Allocate Variables Flag - inblck = FALSE; //Multiline Block Flag - infunc = FALSE; //Inside Function Definition - xstmnt[0] = 0; //Expected Statement - nxtwrd[0] = 0; //Next Word (from DEFINE lookup) - nxtptr = 0; //Pointer to next character in nxtwrd - vrwrtn = FALSE; //Variables Written Flag - rambas = 0; //RAM Base Address - wrtbas = 0; //Write Base Address - zpaddr = 0; //Current Zero-Page Address - invasc = FALSE; //Invert ASCII Flag - mskasc = FALSE; //Set High Bit Flag - fcase = FALSE; //First Case Statement Flag - wrtofs[0] = 0; //Write Offset - xsnvar[0] = 0; //Assigned X Variable Name - ysnvar[0] = 0; //Assigned Y Variable Name - subcnt = 0; //Include Subdirectories - strcpy(cputyp, CPUARG); //Set CPU Type to Default Value - strcpy(incdir, "../include/"); -} - -/* Parse Pointer Dereference Assignment */ -void ppntr(void) { - lsrtrn = FALSE; //Clear RETURN flag - if (xstmnt[0]) ERROR("Expected '%s' statement\n", xstmnt, EXIT_FAILURE) - prcasp(';'); -} - -/* Reads and parses the next Word in Source File */ -void pword(void) { - lsrtrn = FALSE; //Clear RETURN flag - getwrd(); - DEBUG("Parsing Word '%s'\n", word) - if (xstmnt[0]) { - if (wordis(xstmnt)) xstmnt[0] = 0; //Clear xstmnt - else ERROR("Expected '%s' statement\n", xstmnt, EXIT_FAILURE) - } - if (!pmodfr() && !ptype(MTNONE)) pstmnt(); //Parse Statement -} - -/* Process a directive */ -void pdrctv(void) { - skpchr(); //skip '#' - CCMNT('#'); - getwrd(); //read directive into word - DEBUG("Processing directive '%s'\n", word) - if (wordis("DEFINE")) pdefin(); //Parse Define - else if (wordis("INCLUDE")) pincfl(); //Parse Include File - else if (wordis("ERROR")) ERROR("Error \n", 0, EXIT_FAILURE) - else if (wordis("PRAGMA")) pprgma(); - else ERROR("Illegal directive %s encountered\n", word, EXIT_FAILURE) -} - -void prolog(void) { - DEBUG("Writing Assembly Prolog\n", 0) - asmlin(CPUOP,cputyp); - setcmt("Program "); - addcmt(srcnam); - cmtlin(); -} - -void epilog(void) { - if (!vrwrtn) wvrtbl(); //Write Variable Table - if (padcnt) { - SCMNT("PADDING BYTES") - sprintf(word, "$%hhX", padcnt); - asmlin(STROP, word); - } -} - -/* Compile Source Code*/ -void compile(void) { - DEBUG("Starting Compilation\n", 0) - prolog(); - phdrfl(); //Process Header File specified on Command Line - skpchr(); - DEBUG("Parsing Code\n", 0) - while (TRUE) { - skpspc(); - if (match(EOF)) break; //Stop Parsing (End of File) - else if (match('}')) endblk(TRUE); //End Multi-Line Program Block - else if (match('#')) pdrctv(); //Parse Directive - else if (match('/')) skpcmt(TRUE); //Skip Comment - else if (match('*')) ppntr(); //Parse Pointer - else if (isalph()) pword(); //Parse Word - else ERROR("Unexpected character '%c'\n", nxtchr, EXIT_FAILURE) - } - epilog(); -} - -/* Display "Usage" text and exit*/ -void usage(void) { - printf("Usage: c02 sourcefile.c02\n"); - exit(EXIT_FAILURE); -} - -/* Parse Command Line Option */ -int popt(int arg, int argc, char *argv[]) { - char argstr[32]; //Argument String - char opt; //Option - char optarg[32]; //Option Argument - strncpy (argstr, argv[arg], 31); - if (strlen(argstr) != 2) ERROR("malformed option %s\n", argstr, EXIT_FAILURE) - opt = toupper(argstr[1]); - if (strchr("CHS", opt)) { - if (++arg >= argc) ERROR("Option -%c requires an argument\n", opt, EXIT_FAILURE) - strncpy(optarg, argv[arg], 31); - } - DEBUG("Processing Command Line Option -%c\n", argstr[1]) - switch (opt) { - case 'C': - strcpy(cputyp, optarg); - DEBUG("CPU Type set to '%s'\n", cputyp) - break; - case 'H': - strcpy(hdrnam, optarg); - DEBUG("Header Name set to '%s'\n", hdrnam) - break; - case 'S': - strcpy(subdir[subcnt], optarg); - DEBUG("subdir[%d] ", subcnt) - DEBUG("set to '%s'\n", subdir[subcnt]) - subcnt++; - break; - default: - ERROR("Illegal option -%c\n", opt, EXIT_FAILURE) - } - return arg; -} - -/* Parse Command Line Arguments * - * Sets: srcnam - Source File Name (from first arg) * - * outnam - Output File Name (from optional second arg) */ -void pargs(int argc, char *argv[]) { - int arg; - srcnam[0] = 0; - outnam[0] = 0; - DEBUG("Parsing %d arguments\n", argc) - if (argc == 0) usage(); //at least one argument is required - for (arg = 1; arg +#include +#include +#include +#include + +#include "common.h" //Common Code used by all Modules +#include "files.h" //Open and Close Files +#include "asm.h" //Write out Assembly Language +#include "parse.h" //General Code Parsing +#include "vars.h" //Variable Parsing, Lookup, and Allocation +#include "expr.h" //Expression Parsing +#include "label.h" //Label Parsing, Generation, and Lookup +#include "cond.h" //Conditional Parsing +#include "stmnt.h" //Statement Compiling Code +#include "dclrtn.h" //Statement Compiling Code +#include "include.h" //Include File Parsing + +/* Initilize Compiler Variables */ +void init(void) { + DEBUG("Initializing Compiler Variables\n",0) + concnt = 0; //Number of Constants Defined + varcnt = 0; //Number of Variables in Table + lblcnt = 0; //Number of Labels in stack + padcnt = 0; //Number of Padding Bytes at End + curcol = 0; //Current Column in Source Code + curlin = 0; //Current Line in Source Code + alcvar = TRUE; //Allocate Variables Flag + inblck = FALSE; //Multiline Block Flag + infunc = FALSE; //Inside Function Definition + xstmnt[0] = 0; //Expected Statement + nxtwrd[0] = 0; //Next Word (from DEFINE lookup) + nxtptr = 0; //Pointer to next character in nxtwrd + vrwrtn = FALSE; //Variables Written Flag + rambas = 0; //RAM Base Address + wrtbas = 0; //Write Base Address + zpaddr = 0; //Current Zero-Page Address + invasc = FALSE; //Invert ASCII Flag + mskasc = FALSE; //Set High Bit Flag + fcase = FALSE; //First Case Statement Flag + wrtofs[0] = 0; //Write Offset + xsnvar[0] = 0; //Assigned X Variable Name + ysnvar[0] = 0; //Assigned Y Variable Name + subcnt = 0; //Include Subdirectories + strcpy(cputyp, CPUARG); //Set CPU Type to Default Value + strcpy(incdir, "../include/"); +} + +/* Parse Pointer Dereference Assignment */ +void ppntr(void) { + lsrtrn = FALSE; //Clear RETURN flag + if (xstmnt[0]) ERROR("Expected '%s' statement\n", xstmnt, EXIT_FAILURE) + prcasp(';'); +} + +/* Reads and parses the next Word in Source File */ +void pword(void) { + lsrtrn = FALSE; //Clear RETURN flag + getwrd(); + DEBUG("Parsing Word '%s'\n", word) + if (xstmnt[0]) { + if (wordis(xstmnt)) xstmnt[0] = 0; //Clear xstmnt + else ERROR("Expected '%s' statement\n", xstmnt, EXIT_FAILURE) + } + if (!pmodfr() && !ptype(MTNONE)) pstmnt(); //Parse Statement +} + +/* Process a directive */ +void pdrctv(void) { + skpchr(); //skip '#' + CCMNT('#'); + getwrd(); //read directive into word + DEBUG("Processing directive '%s'\n", word) + if (wordis("DEFINE")) pdefin(); //Parse Define + else if (wordis("INCLUDE")) pincfl(); //Parse Include File + else if (wordis("ERROR")) ERROR("Error \n", 0, EXIT_FAILURE) + else if (wordis("PRAGMA")) pprgma(); + else ERROR("Illegal directive %s encountered\n", word, EXIT_FAILURE) +} + +void prolog(void) { + DEBUG("Writing Assembly Prolog\n", 0) + asmlin(CPUOP,cputyp); + setcmt("Program "); + addcmt(srcnam); + cmtlin(); +} + +void epilog(void) { + if (!vrwrtn) wvrtbl(); //Write Variable Table + if (padcnt) { + SCMNT("PADDING BYTES") + sprintf(word, "$%hhX", padcnt); + asmlin(STROP, word); + } +} + +/* Compile Source Code*/ +void compile(void) { + DEBUG("Starting Compilation\n", 0) + prolog(); + phdrfl(); //Process Header File specified on Command Line + skpchr(); + DEBUG("Parsing Code\n", 0) + while (TRUE) { + skpspc(); + if (match(EOF)) break; //Stop Parsing (End of File) + else if (match('}')) endblk(TRUE); //End Multi-Line Program Block + else if (match('#')) pdrctv(); //Parse Directive + else if (match('/')) skpcmt(TRUE); //Skip Comment + else if (match('*')) ppntr(); //Parse Pointer + else if (isalph()) pword(); //Parse Word + else ERROR("Unexpected character '%c'\n", nxtchr, EXIT_FAILURE) + } + epilog(); +} + +/* Display "Usage" text and exit*/ +void usage(void) { + printf("Usage: c02 sourcefile.c02\n"); + exit(EXIT_FAILURE); +} + +/* Parse Command Line Option */ +int popt(int arg, int argc, char *argv[]) { + char argstr[32]; //Argument String + char opt; //Option + char optarg[32]; //Option Argument + strncpy (argstr, argv[arg], 31); + if (strlen(argstr) != 2) ERROR("malformed option %s\n", argstr, EXIT_FAILURE) + opt = toupper(argstr[1]); + if (strchr("CHS", opt)) { + if (++arg >= argc) ERROR("Option -%c requires an argument\n", opt, EXIT_FAILURE) + strncpy(optarg, argv[arg], 31); + } + DEBUG("Processing Command Line Option -%c\n", argstr[1]) + switch (opt) { + case 'D': + debug = TRUE; + DEBUG("Debug output enable\n", 0) + break; + case 'C': + strcpy(cputyp, optarg); + DEBUG("CPU Type set to '%s'\n", cputyp) + break; + case 'H': + strcpy(hdrnam, optarg); + DEBUG("Header Name set to '%s'\n", hdrnam) + break; + case 'S': + strcpy(subdir[subcnt], optarg); + DEBUG("subdir[%d] ", subcnt) + DEBUG("set to '%s'\n", subdir[subcnt]) + subcnt++; + break; + default: + ERROR("Illegal option -%c\n", opt, EXIT_FAILURE) + } + return arg; +} + +/* Parse Command Line Arguments * + * Sets: srcnam - Source File Name (from first arg) * + * outnam - Output File Name (from optional second arg) */ +void pargs(int argc, char *argv[]) { + int arg; + srcnam[0] = 0; + outnam[0] = 0; + DEBUG("Parsing %d arguments\n", argc) + if (argc == 0) usage(); //at least one argument is required + for (arg = 1; arg -#include -#include -#include -#include -#include -#include "common.h" - -struct timespec curtim; //Current Time - -/* Error - Print Input File name & position and exit */ -void exterr(int errnum) { - fprintf(stderr, "Line %d Column %d of File %s\n", curlin, curcol, inpnam); - exit(errnum); -} - -/* Error - print "Expected" error message * - and exit with general failure code * - Args: expected - Description of what was expected */ -void expctd(char *expstr) { - fprintf(stderr, "Expected %s, but found '%c'\n", expstr, nxtchr); - exterr(EXIT_FAILURE); -} - -/* Print current position in file */ -void prtpos(void) { if (inpnam[0]) printf("(%s: %d,%d) ", inpnam, curlin, curcol); } - -/* Initialize elapsed time counter */ -void initim(void) { - timespec_get (&curtim, TIME_UTC); - bgntim = curtim.tv_sec; -} - -/* Print elapsed time */ -void prttim(void) { - timespec_get (&curtim, TIME_UTC); - printf("[%d", curtim.tv_sec - bgntim); - printf(".%06d]",curtim.tv_nsec/1000); -} - -/* Set comment to string */ -void setcmt(char *s) { strcpy(cmtasm, s); } - -/* Append string to comment */ -void addcmt(char *s) { - if (strlen(cmtasm)+strlen(s)<73) strcat(cmtasm, s); -} - -/* Append character to comment */ -void chrcmt(char c) { - if (strlen(cmtasm)>72) return; - if (cmtasm[0] == 0 && c == ' ') return; - int i = strlen(cmtasm); - cmtasm[i++] = c; - cmtasm[i] = 0; -} +/************************************* + * C02 Common Definitions & Routines * + *************************************/ + +#include +#include +#include +#include +#include +#include "common.h" + +/* Error - Print Input File name & position and exit */ +void exterr(int errnum) { + fprintf(stderr, "Line %d Column %d of File %s\n", curlin, curcol, inpnam); + exit(errnum); +} + +/* Error - print "Expected" error message * + and exit with general failure code * + Args: expected - Description of what was expected */ +void expctd(char *expstr) { + fprintf(stderr, "Expected %s, but found '%c'\n", expstr, nxtchr); + exterr(EXIT_FAILURE); +} + +/* Print current position in file */ +void prtpos(void) { if (inpnam[0]) printf("(%s: %d,%d) ", inpnam, curlin, curcol); } + +/* Set comment to string */ +void setcmt(char *s) { strcpy(cmtasm, s); } + +/* Append string to comment */ +void addcmt(char *s) { + if (strlen(cmtasm)+strlen(s)<73) strcat(cmtasm, s); +} + +/* Append character to comment */ +void chrcmt(char c) { + if (strlen(cmtasm)>72) return; + if (cmtasm[0] == 0 && c == ' ') return; + int i = strlen(cmtasm); + cmtasm[i++] = c; + cmtasm[i] = 0; +} diff --git a/src/common.h b/src/common.h index 7ebee84..4e7cdaf 100644 --- a/src/common.h +++ b/src/common.h @@ -1,98 +1,96 @@ -/************************************* - * C02 Common Definitions & Routines * - *************************************/ - -#define FNAMLEN 255 //Maximum File Name Length -#define LINELEN 255 //Maximum Input/Output Line Length -#define CONLEN 6 //Maximum Constant Name Length -#define MAXCON 255 //Maximum Number of Constants -#define STCLEN 6 //Maximum Struct Name Length -#define MAXSTC 32 //Maximum Number of Stuctures -#define STMLEN 6 //Maximum Struct Member Name Length -#define MAXSTM 255 //Maximum Number of Stucture Members -#define VARLEN 6 //Maximum Variable Name Length -#define MAXVAR 255 //Maximum Number of Variables -#define MAXTRM 16 //Maximum Terms in Stack -#define DATASPC 4096 //Space to Allocate for Variable Data -#define SUBMAX 4 //Maximum Number of Sub Directories - -#define LABLEN 6 //Maximum Program Label Length -#define MAXLAB 255 //Maximum Number of Program Labels - -#define LBLLEN 6 //Maximum Label Length -#define LBLFMT "L_%04d" //Label Format -#define LABSFX ":" //Label Suffix -#define MAXLBL 15 //Maximum Number of Labels (Nesting Depth) -#define LOCPFX "." //Local Variable Prefix - -#define CPUOP "PROCESSOR" //Target CPU Pseudo-Operator -#define CPUARG "6502" //Target CPU Operand -#define ORGOP "ORG" //Origin Pseudo-Op -#define EQUOP "EQU" //Equate Pseudo-Op -#define BYTEOP "BYTE" //Define Byte Pseudo-Op -#define STROP "DS" //Define String Pseudo-Op -#define ALNOP "ALIGN" //Align Pseudo-Op -#define USEGOP "SEG.U" //Uninitalized Segment Pseudo-Op -#define LOCOP "SUBROUTINE" //Local Variable Boundary Pseudo-Op - -#define ASMFMT "%-7s %-3s %-12s %s\n" //Assembly Language Line printf Format - -/* Internal defines */ -#define TRUE -1 -#define FALSE 0 - -void initim(); //Initialize elapsed time counter -void prtpos(); //Print current file name and position -void prttim(); //Print elapsed time -#define DEBUG(fmt, val) {if (debug) {prtpos(); prttim(); printf(fmt, val);}} -#define DETAIL(fmt, val) {if (debug) printf(fmt, val);} -#define ERROR(fmt, val, err) {fprintf(stderr, fmt, val);exterr(err);} - -int debug; //Print Debug Info (TRUE or FALSE) -int cmos; //Flag: Use 65C02 Instruction Set - -int gencmt; //Generate Assembly Language Comments -char asmcmt[LINELEN]; //Processed Assembly Language Comment - -int curcol, curlin; //Position in Source Code -int savcol, savlin; //Save Position in Source Code - -int bgntim; //Starting Time - -int nxtchr; //Next Character of Source File to Process -int nxtupc; //Next Character Converted to Uppercase -int savchr; //Holds nxtchr when switching input files - -int wrdlen; //Length of Parsed Word -char word[LINELEN]; //Word parsed from source file -char uword[LINELEN]; //Word converted to uppercase -int pstlen; //Length of Parsed String -char pstrng[LINELEN]; //String parsed fron source file -char cmtasm[LINELEN]; //Assembly Language Comment Text -char cputyp[LINELEN]; //CPU Type - -char hdrnam[FNAMLEN]; //Header File Name -char incdir[FNAMLEN]; //Include File Directory -char inpnam[FNAMLEN]; //Input File Name -char subdir[SUBMAX][FNAMLEN]; //Include File SubDirectory -int subcnt; //Number of Include Directories -int subidx; //Index into subdir[] - -int alcvar; //Allocate Variables Flag -int inblck; //Multiline Block Flag -int infunc; //Inside Function Definition Flag -int lsrtrn; //Last Statement was a Return Flag -int fcase; //First Case Statement Flag - -int padcnt; //Number of Padding Bytes at End of Program - -void exterr(int errnum); //Print current file name & position and exit -void expctd(char *expected); //Print Expected message and exit - -void addcmt(char *s); //Append string to comment -void chrcmt(char c); //Append character to comment -void setcmt(char *s); //Set comment to string -#define SCMNT(str) if (gencmt) {setcmt(str);} -#define ACMNT(str) if (gencmt) {addcmt(str);} -#define CCMNT(chr) if (gencmt) {chrcmt(chr);} -#define LCMNT(str) if (gencmt) {setcmt(str); cmtlin();} +/************************************* + * C02 Common Definitions & Routines * + *************************************/ + +#define FNAMLEN 255 //Maximum File Name Length +#define LINELEN 255 //Maximum Input/Output Line Length +#define CONLEN 6 //Maximum Constant Name Length +#define MAXCON 255 //Maximum Number of Constants +#define STCLEN 6 //Maximum Struct Name Length +#define MAXSTC 32 //Maximum Number of Stuctures +#define STMLEN 6 //Maximum Struct Member Name Length +#define MAXSTM 255 //Maximum Number of Stucture Members +#define VARLEN 6 //Maximum Variable Name Length +#define MAXVAR 255 //Maximum Number of Variables +#define MAXTRM 16 //Maximum Terms in Stack +#define DATASPC 4096 //Space to Allocate for Variable Data +#define SUBMAX 4 //Maximum Number of Sub Directories + +#define LABLEN 6 //Maximum Program Label Length +#define MAXLAB 255 //Maximum Number of Program Labels + +#define LBLLEN 6 //Maximum Label Length +#define LBLFMT "L_%04d" //Label Format +#define LABSFX ":" //Label Suffix +#define MAXLBL 15 //Maximum Number of Labels (Nesting Depth) +#define LOCPFX "." //Local Variable Prefix + +#define CPUOP "PROCESSOR" //Target CPU Pseudo-Operator +#define CPUARG "6502" //Target CPU Operand +#define ORGOP "ORG" //Origin Pseudo-Op +#define EQUOP "EQU" //Equate Pseudo-Op +#define BYTEOP "BYTE" //Define Byte Pseudo-Op +#define STROP "DS" //Define String Pseudo-Op +#define ALNOP "ALIGN" //Align Pseudo-Op +#define USEGOP "SEG.U" //Uninitalized Segment Pseudo-Op +#define LOCOP "SUBROUTINE" //Local Variable Boundary Pseudo-Op + +#define ASMFMT "%-7s %-3s %-12s %s\n" //Assembly Language Line printf Format + +/* Internal defines */ +#define TRUE -1 +#define FALSE 0 + +void prtpos(); //Print current file name and position +#define DEBUG(fmt, val) {if (debug) {prtpos(); printf(fmt, val);}} +#define DETAIL(fmt, val) {if (debug) printf(fmt, val);} +#define ERROR(fmt, val, err) {fprintf(stderr, fmt, val);exterr(err);} + +int debug; //Print Debug Info (TRUE or FALSE) +int cmos; //Flag: Use 65C02 Instruction Set + +int gencmt; //Generate Assembly Language Comments +char asmcmt[LINELEN]; //Processed Assembly Language Comment + +int curcol, curlin; //Position in Source Code +int savcol, savlin; //Save Position in Source Code + +int bgntim; //Starting Time + +int nxtchr; //Next Character of Source File to Process +int nxtupc; //Next Character Converted to Uppercase +int savchr; //Holds nxtchr when switching input files + +int wrdlen; //Length of Parsed Word +char word[LINELEN]; //Word parsed from source file +char uword[LINELEN]; //Word converted to uppercase +int pstlen; //Length of Parsed String +char pstrng[LINELEN]; //String parsed fron source file +char cmtasm[LINELEN]; //Assembly Language Comment Text +char cputyp[LINELEN]; //CPU Type + +char hdrnam[FNAMLEN]; //Header File Name +char incdir[FNAMLEN]; //Include File Directory +char inpnam[FNAMLEN]; //Input File Name +char subdir[SUBMAX][FNAMLEN]; //Include File SubDirectory +int subcnt; //Number of Include Directories +int subidx; //Index into subdir[] + +int alcvar; //Allocate Variables Flag +int inblck; //Multiline Block Flag +int infunc; //Inside Function Definition Flag +int lsrtrn; //Last Statement was a Return Flag +int fcase; //First Case Statement Flag + +int padcnt; //Number of Padding Bytes at End of Program + +void exterr(int errnum); //Print current file name & position and exit +void expctd(char *expected); //Print Expected message and exit + +void addcmt(char *s); //Append string to comment +void chrcmt(char c); //Append character to comment +void setcmt(char *s); //Set comment to string +#define SCMNT(str) if (gencmt) {setcmt(str);} +#define ACMNT(str) if (gencmt) {addcmt(str);} +#define CCMNT(chr) if (gencmt) {chrcmt(chr);} +#define LCMNT(str) if (gencmt) {setcmt(str); cmtlin();} diff --git a/src/expr.c b/src/expr.c index 807cee4..db8b507 100644 --- a/src/expr.c +++ b/src/expr.c @@ -1,454 +1,457 @@ -/*********************************** - * C02 Expression Parsing Routines * - ***********************************/ - -#include -#include -#include -#include -#include -#include "common.h" -#include "asm.h" -#include "parse.h" -#include "vars.h" -#include "label.h" -#include "expr.h" - -/* Push Term and Operator onto Stack */ -void pshtrm(void) { - if (trmidx >= MAXTRM) ERROR("Maximum Function Call/Array Index Depth Exceeded", 0, EXIT_FAILURE) - oprstk[trmidx] = oper; //Put Current Operator on Stack - strcpy(trmstk[trmidx], term); //Put Current Term on Stack - trmidx++; //Increment Stack Pointer - DEBUG("expr.pshtrm: Pushed term %s ", term) - DETAIL("and operator '%onto stack'\n", oper) -} - -/* Pop Term and Operator off Stack */ -void poptrm(void) { - trmidx--; //Decrement Stack Pointer - strcpy(term, trmstk[trmidx]); //Restore Current Term from Stack - oper = oprstk[trmidx]; //Restore Current Operator from Stack - DEBUG("expr.pshtrm: Popped term %s ", term) - DETAIL("and operator '%c' off stack\n", oper) -} - -/* Parse value (literal or identifier) * - * Args: alwreg - allow registers * - 8 alwcon - allow constants * - * Sets: value - the value (as a string) * - * valtyp - value type */ -void prsval(int alwreg, int alwcon) { - DEBUG("expr.prsval: Parsing value\n", 0) - skpspc(); - if (islpre()) prslit(); //Parse Literal - else if (isalph()) prsvar(alwreg, alwcon); //Parse Variable - else if (isbtop()) prsbop(); //Parse Byte Operator - else expctd("literal or variable"); - DEBUG("expr.prsval: Parsed value %s ", value) - DETAIL("of type %d\n", valtyp) - skpspc(); -} - -/* Process Unary Minus */ -void prcmns(void) { - DEBUG("Processing unary minus", 0) - asmlin("LDA", "#$00"); //Handle Unary Minus -} - -/* Parse array index * - * Args: clbrkt - require closing bracket * - * Sets: value - array index or * - * "" if no index defined */ -void prsidx(int clbrkt) { - expect('['); - prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants - DEBUG("expr.prsidx: Parsed array index '%s'\n", value) - if (clbrkt) expect(']'); -} - -/* Process Simple Array Index * - * Uses: term - array variable name * - * valtyp - array index value type * - * value - array index as string * - * word - array index raw string * - * Sets: term - modified variable name */ -void prcsix(void) { - DEBUG("expr.prcsix: Processing simple array index %s\n", word); - if (valtyp == LITERAL) { - strcat(term, "+"); - strcat(term, word); - } - else if (strcmp(value, "Y")==0) - strcat(term, ",Y"); - else { - if (strcmp(value, "A")==0) asmlin("TAX", ""); - else if (strcmp(value, "X")!=0) asmlin("LDX", value); - strcat(term, ",X"); - } - DEBUG("expr.prcsix: Set term to %s\n", term); -} - -/* Process Expression Array Index */ -void prcxix(void) { - DEBUG("expr.prcxix: Processing Expression Array Index", 0) - pshtrm(); //Push Array Variable onto Term Stack - if (trmcnt) asmlin("PHA", ""); //Save Accumulator if not first term - prcftm(FALSE); //Process First Term of Expression - prsrxp(']'); //Parse Rest of Expression - asmlin("TAX", ""); //Transfer Result of Expression to Index Register - if (trmcnt) asmlin("PLA", ""); //Restore Accumator if not first term - poptrm(); //Pop Array Variable off Term Stack - strcat(term, ",X"); - DEBUG("expr.prcxix: Set term to %s\n", term); -} - -/* Check for, Parse, and Process Index */ -void chkidx(void) { - //DEBUG("Checking for Array Index with valtyp=%d\n", valtyp) - if (valtyp == ARRAY) { - if (look('-')) { - prcmns(); - prcxix(); - } - else { - prsidx(FALSE); - if (valtyp > REGISTER) prcxix(); - else if (look(']')) prcsix(); - else prcxix(); - } - } -} - -/* Parse Pointer * - * Sets: term - Compiled Pointer */ -void prsptr(void) { - DEBUG("Parsing pointer\n", 0) - expect('*'); //Pointer Dereference Operator - prsvar(FALSE,FALSE); //Parse Variable to Dereference - strcpy(term, value); - if (varble.modifr != MTZP) ERROR("Illegal dereference of non-pointer variable %s.\n", value, EXIT_FAILURE) - DEBUG("expr.prsptr: Set term to %s\n", term); -} - -/* Process Pointer Index * - * Sets: term - Compiled Pointer */ -void prcptx(char *index) { - DEBUG("expr.prcptx: Processing Dereferenced Pointer %s ", term) - DETAIL("index [%s]\n", index) - if (strcmp(index,"X")==0) ERROR("Illegal use of register X\n", 0, EXIT_FAILURE); - if (strcmp(index,"A")==0) asmlin("TAY", ""); - else if (strcmp(index,"Y") != 0) asmlin("LDY", index); -} - -/* Process Pointer * - * Sets: term - Compiled Pointer */ -int prcptr(void) { - prsptr(); - DEBUG("expr.prcptr: Dereferencing Pointer %s\n", value); - if (valtyp == ARRAY) { - prsidx(TRUE); - prcptx(value); - sprintf(word, "(%s),Y", term); - } else if (cmos) { - sprintf(word, "(%s)", term); - } else { - asmlin("LDY","0"); - sprintf(word, "(%s),Y", term); - } - strcpy(term, word); - DEBUG("expr.prcptr: Set term to %s\n", term); - return FALSE; //Return Value Not an Integer -} - -/* Parse Term in Expression * - * Sets: term - the term (as a string) * - * Returns: TRUE if term is an integer */ -int prstrm(int alwint) { - DEBUG("Parsing term\n", 0) - if (match('*')) return prcptr(); //Parse and Deference Pointer - prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants - if (valtyp == FUNCTION) ERROR("Function call only allowed in first term\n", 0, EXIT_FAILURE) - strcpy(term, value); - if (valtyp == VARIABLE && prcivr(alwint)) return TRUE; - DEBUG("expr.prstrm: Parsed term %s\n", term) - chkidx(); //Check for Array Index - skpspc(); - return FALSE; -} - -/* Process Address Reference - * Args: adract = Address Action (adacts) * - * symbol = Symbol to Process */ -void prcadr(int adract, char* symbol) { - DEBUG("Processing address '%s'\n", word) - strcpy(word,"#>("); - strcat(word,symbol); - strcat(word,")"); - if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } - else asmlin("LDY", word); - strcpy(word,"#<("); - strcat(word,symbol); - strcat(word,")"); - if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } - else asmlin("LDX", word); -} - -/* Parse and Compile Address of Operator * - * Args: adract = Address Action */ -void prsadr(int adract) { - DEBUG("Parsing address\n", 0) - if (isnpre()) prsnum(0xFFFF); - else { - getwrd(); - if (fndlab(word)) strcpy(value, word); - else prsvrw(FALSE, TRUE); - } - if (adract) prcadr(adract, value); //Compile Address Reference - else strcpy(word, value); //Save for Calling Routine -} - -/* Parse and Create Anonymous String * - * Args: adract = Address Action * - * alwstr = Allow String */ -void prsstr(int adract, int alwstr) { - if (!alwstr) ERROR("Illegal String Reference", 0, EXIT_FAILURE) - DEBUG("Parsing anonymous string\n", 0) - newlbl(vrname); //Generate Variable Name - value[0] = 0; //Use Variable Size 0 - setvar(MTNONE, VTCHAR); //Set Variable Name, Type, and Size - prsdts(); //Parse Data String - setdat(); //Set Variable Data - varcnt++; //Increment Variable Counter - if (adract) prcadr(adract, vrname); //Compile Address Reference - else strcpy(word, vrname); //Save for Calling Routine -} - -/* Check for and Process Address or String * - * Args: adract = Address Action * - * alwstr = Allow String */ -int chkadr(int adract, int alwstr) { - DEBUG("Checking for Address or String\n", 0) - int result = TRUE; - if (look('&')) prsadr(adract); - else if (match('"')) prsstr(adract, alwstr); - else result = FALSE; - skpspc(); - return result; -} - -/* Parse Byte Operator */ -void prsbop(void) { - char byteop = getnxt(); - CCMNT(byteop); - DEBUG("Parsing byte operator '%c'\n", byteop) - if (chkadr(FALSE, FALSE)) { - sprintf(value, "%c(%s)", byteop, word); - valtyp = LITERAL; - } else { - reqvar(FALSE); - if (vartyp != VTINT) ERROR("Integer Value Expected\n", 0, EXIT_FAILURE) - if (byteop == '>') strcat(value, "+1"); - vartyp = VTCHAR; - } - DEBUG("Set value to \"%s\"\n", value) -} - -/* Parse Function Argument or Return Values */ -void prsfpr(char trmntr) { - int pusha = 0; int pushy = 0; //A and Y Arguments Pushed - if (!chkadr(ADLDYX, TRUE) && isxpre() || match('.')) { - if (look('.')) pusha = 255; - else {if (prsxpf(0)) goto prsfne;} - if (look(',') && !chkadr(ADLDYX, TRUE)) { - if (look('.')) { - pushy = -1; - } - else { - if (look('(')) { - if (pusha==0) {pusha = 1; asmlin("PHA","");} //Save A on Stack - prsxpr(')'); asmlin("TAY", ""); //Evaluate Expression, and Copy to Y - } - else { - if (prstrm(TRUE)) goto prsfne; - asmlin("LDY", term); - } - } - if (look(',')) { - if (look('(')) { - if (pusha==0) {pusha = 1; asmlin("PHA","");} //Save A on Stack - if (pushy==0) {pushy = 1; asmlin("PHA",""); asmlin("PHY","");} //Save Y on Stack - prsxpr(')'); asmlin("TAX", ""); //Evaluate Expression, and Copy to X - } - else { - prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants - if (valtyp > VARIABLE) ERROR("Illegal Value Function Argument\n", 0, EXIT_FAILURE); - if (valtyp == VARIABLE && vartyp != VTCHAR) ERROR("Illegal Variable Type\n", 0, EXIT_FAILURE); - asmlin("LDX", value); - } - } - } - } - prsfne: - if (pushy==1) {asmlin("PLA",""); asmlin("TAY","");} //Pull Y Off Stack - if (pusha==1) asmlin("PLA",""); //Pull A Off Stack - expect(trmntr); -} - -/* Parse function call */ -void prsfnc(char trmntr) { - DEBUG("Processing Function Call '%s'\n", term) - //int argexp = FALSE; //Expression(s) in second and third argument - pshtrm(); //Push Function Name onto Term Stack - skpchr(); //skip open paren - CCMNT('('); - prsfpr(')'); //Parse Function Parameters - expect(trmntr); - poptrm(); //Pop Function Name off Term Stack - asmlin("JSR", term); - skpspc(); -} - -/* Process Integer Variable */ -void prcvri(void) { - DEBUG("Processing Integer Variable '%s'\n", value) - asmlin("LDX", value); - strcat(value, "+1"); - asmlin("LDY", value); -} - -/* Process Integer Variable in Term * - * Args: alwint = Allow Integer-Like Variable * - * Returns: Integer-Like Variable Processed - TRUE/FALSE */ -int prcivr(int alwint) { - switch (vartyp) { - case VTINT: - if (!alwint) ERROR("Illegal Use of Integer Variable %s\n", word, EXIT_FAILURE) - prcvri(); - return TRUE; - case VTARRAY: - if (!alwint) ERROR("Illegal Reference to Array %s\n", word, EXIT_FAILURE) - prcadr(ADNONE, term); - return TRUE; - case VTSTRUCT: - if (!alwint) ERROR("Illegal Reference to Struct %s\n", word, EXIT_FAILURE) - prcadr(ADNONE, term); - return TRUE; - default: - return FALSE; - } -} - -/* Process first term of expression */ -int prcftm(int alwint) { - DEBUG("Processing first term '%s'\n", value) - strcpy(term, value); - if (valtyp == VARIABLE && prcivr(alwint)) return TRUE; - if (valtyp == FUNCTION) prsfnc(0); //Parse Expression Function - else if (wordis("A")) return FALSE; - else if (wordis("X")) asmlin("TXA", ""); - else if (wordis("Y")) asmlin("TYA", ""); - else { chkidx(); asmlin("LDA", term); } - return FALSE; -} - -/* Parse first term of expession * - * First term can include function calls */ -int prsftm(int alwint) { - DEBUG("Parsing first term\n", 0) - if (match('*')) { - prcptr(); //Parse and Deference Pointer - asmlin("LDA", term); - return FALSE; - } - prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants - return prcftm(alwint); -} - -/* Process Arithmetic or Bitwise Operator * - * and the term that follows it */ -void prcopr(void) { - DEBUG("Processing operator '%c'\n", oper) - switch(oper) { - case '+': asmlin("CLC", ""); asmlin("ADC", term); break; //Addition - case '-': asmlin("SEC", ""); asmlin("SBC", term); break; //Subtraction - case '&': asmlin("AND", term); break; //Bitwise AND - case '!': //For systems that don't have pipe in character set - case '|': asmlin("ORA", term); break; //Bitwise OR - case '^': asmlin("EOR", term); break; //Bitwise XOR - default: ERROR("Unrecognized operator '%c'\n", oper, EXIT_FAILURE) - } - oper = 0; -} - -/* Parse Remainder of Expression */ -void prsrxp(char trmntr) { - skpspc(); - while (isoper()) { - trmcnt++; //Increment Expression Depth - prsopr(); //Parse Operator - prstrm(FALSE); //Parse Term - prcopr(); //Process Operator - trmcnt--; //Decrement Expression Depth - } - expect(trmntr); -} - -int prsxpp(char trmntr, int alwint) { - DEBUG("Parsing expression\n", 0) - skpspc(); - trmcnt = 0; //Initialize Expression Depth - if (match('-')) prcmns(); //Process Unary Minus - else if (prsftm(alwint)) return TRUE; //Parse First Term - prsrxp(trmntr); //Parse Remainder of Express - return FALSE; -} - -/* Parse and compile expression */ -void prsxpr(char trmntr) { - prsxpp(trmntr, FALSE); -} - -/* Parse and compile function parameter expression * - * Returns: TRUE if Integer Expression */ -int prsxpf(char trmntr) { - return prsxpp(trmntr, TRUE); -} - -/* Parse and Compile Integer Expression * - * (Address, Integer Literal, Variable, * - * Struct Member, or Function) * - * Args: trmntr - expression terminator * - * asmxpr - assemble expression * - * Sets: value - Parsed Value or Symbol */ -void prsxpi(char trmntr, int asmxpr) { - skpspc(); - DEBUG("Parsing integer expression\n", 0) - if (!chkadr(TRUE, FALSE)) { - if (isnpre()) { - DEBUG("Parsing Integer Literal\n", 0) - int number = prsnum(0xFFFF); //Parse Number into value - if (asmxpr) { - sprintf(value, "#%d", number & 0xFF); asmlin("LDX", value); - sprintf(value, "#%d", number >> 8); asmlin("LDY", value); - } - } else if (isalph()) { - prsvar(FALSE, TRUE); - if (valtyp == FUNCTION) { - strcpy(term, value); - DEBUG("expr.prsxpi: Set term to %s\n", term) - prsfnc(0); //Parse Expression Function - } else if (valtyp == STRUCTURE) { - prsmbr(value); - if (vartyp != VTINT) ERROR("Illegal Member %s In Integer Expression", value, EXIT_FAILURE) - } else if (valtyp == VARIABLE && vartyp == VTINT) { - if (asmxpr) prcvri(); //Process Integer Variable - } else { - ERROR("Illegal Variable %s In Integer Expression", value, EXIT_FAILURE) - } - } else { - ERROR("Expected Integer Value or Function\n", 0, EXIT_FAILURE); - } - } - expect(trmntr); -} +/*********************************** + * C02 Expression Parsing Routines * + ***********************************/ + +#include +#include +#include +#include +#include +#include "common.h" +#include "asm.h" +#include "parse.h" +#include "vars.h" +#include "label.h" +#include "expr.h" + +/* Push Term and Operator onto Stack */ +void pshtrm(void) { + if (trmidx >= MAXTRM) ERROR("Maximum Function Call/Array Index Depth Exceeded", 0, EXIT_FAILURE) + oprstk[trmidx] = oper; //Put Current Operator on Stack + strcpy(trmstk[trmidx], term); //Put Current Term on Stack + trmidx++; //Increment Stack Pointer + DEBUG("expr.pshtrm: Pushed term %s ", term) + DETAIL("and operator '%onto stack'\n", oper) +} + +/* Pop Term and Operator off Stack */ +void poptrm(void) { + trmidx--; //Decrement Stack Pointer + strcpy(term, trmstk[trmidx]); //Restore Current Term from Stack + oper = oprstk[trmidx]; //Restore Current Operator from Stack + DEBUG("expr.pshtrm: Popped term %s ", term) + DETAIL("and operator '%c' off stack\n", oper) +} + +/* Parse value (literal or identifier) * + * Args: alwreg - allow registers * + 8 alwcon - allow constants * + * Sets: value - the value (as a string) * + * valtyp - value type */ +void prsval(int alwreg, int alwcon) { + DEBUG("expr.prsval: Parsing value\n", 0) + skpspc(); + if (islpre()) prslit(); //Parse Literal + else if (isalph()) prsvar(alwreg, alwcon); //Parse Variable + else if (isbtop()) prsbop(); //Parse Byte Operator + else expctd("literal or variable"); + DEBUG("expr.prsval: Parsed value %s ", value) + DETAIL("of type %d\n", valtyp) + skpspc(); +} + +/* Process Unary Minus */ +void prcmns(void) { + DEBUG("Processing unary minus", 0) + asmlin("LDA", "#$00"); //Handle Unary Minus +} + +/* Parse array index * + * Args: clbrkt - require closing bracket * + * Sets: value - array index or * + * "" if no index defined */ +void prsidx(int clbrkt) { + expect('['); + prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants + DEBUG("expr.prsidx: Parsed array index '%s'\n", value) + if (clbrkt) expect(']'); +} + +/* Process Simple Array Index * + * Uses: term - array variable name * + * valtyp - array index value type * + * value - array index as string * + * word - array index raw string * + * Sets: term - modified variable name */ +void prcsix(void) { + DEBUG("expr.prcsix: Processing simple array index %s\n", word); + if (valtyp == LITERAL) { + strcat(term, "+"); + strcat(term, word); + } + else if (strcmp(value, "Y")==0) + strcat(term, ",Y"); + else { + if (strcmp(value, "A")==0) asmlin("TAX", ""); + else if (strcmp(value, "X")!=0) asmlin("LDX", value); + strcat(term, ",X"); + } + DEBUG("expr.prcsix: Set term to %s\n", term); +} + +/* Process Expression Array Index */ +void prcxix(void) { + DEBUG("expr.prcxix: Processing Expression Array Index", 0) + pshtrm(); //Push Array Variable onto Term Stack + if (trmcnt) asmlin("PHA", ""); //Save Accumulator if not first term + prcftm(FALSE); //Process First Term of Expression + prsrxp(']'); //Parse Rest of Expression + asmlin("TAX", ""); //Transfer Result of Expression to Index Register + if (trmcnt) asmlin("PLA", ""); //Restore Accumator if not first term + poptrm(); //Pop Array Variable off Term Stack + strcat(term, ",X"); + DEBUG("expr.prcxix: Set term to %s\n", term); +} + +/* Check for, Parse, and Process Index */ +void chkidx(void) { + //DEBUG("Checking for Array Index with valtyp=%d\n", valtyp) + if (valtyp == ARRAY) { + if (look('-')) { + prcmns(); + prcxix(); + } + else { + prsidx(FALSE); + if (valtyp > REGISTER) prcxix(); + else if (look(']')) prcsix(); + else prcxix(); + } + } +} + +/* Parse Pointer * + * Sets: term - Compiled Pointer */ +void prsptr(void) { + DEBUG("Parsing pointer\n", 0) + expect('*'); //Pointer Dereference Operator + prsvar(FALSE,FALSE); //Parse Variable to Dereference + strcpy(term, value); + if (varble.modifr != MTZP) ERROR("Illegal dereference of non-pointer variable %s.\n", value, EXIT_FAILURE) + DEBUG("expr.prsptr: Set term to %s\n", term); +} + +/* Process Pointer Index * + * Sets: term - Compiled Pointer */ +void prcptx(char *index) { + DEBUG("expr.prcptx: Processing Dereferenced Pointer %s ", term) + DETAIL("index [%s]\n", index) + if (strcmp(index,"X")==0) ERROR("Illegal use of register X\n", 0, EXIT_FAILURE); + if (strcmp(index,"A")==0) asmlin("TAY", ""); + else if (strcmp(index,"Y") != 0) asmlin("LDY", index); +} + +/* Process Pointer * + * Sets: term - Compiled Pointer */ +int prcptr(void) { + prsptr(); + DEBUG("expr.prcptr: Dereferencing Pointer %s\n", value); + if (valtyp == ARRAY) { + prsidx(TRUE); + prcptx(value); + sprintf(word, "(%s),Y", term); + } else if (cmos) { + sprintf(word, "(%s)", term); + } else { + asmlin("LDY","0"); + sprintf(word, "(%s),Y", term); + } + strcpy(term, word); + DEBUG("expr.prcptr: Set term to %s\n", term); + return FALSE; //Return Value Not an Integer +} + +/* Parse Term in Expression * + * Sets: term - the term (as a string) * + * Returns: TRUE if term is an integer */ +int prstrm(int alwint) { + DEBUG("Parsing term\n", 0) + if (match('*')) return prcptr(); //Parse and Deference Pointer + prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants + if (valtyp == FUNCTION) ERROR("Function call only allowed in first term\n", 0, EXIT_FAILURE) + strcpy(term, value); + if (valtyp == VARIABLE && prcivr(alwint)) return TRUE; + DEBUG("expr.prstrm: Parsed term %s\n", term) + chkidx(); //Check for Array Index + skpspc(); + return FALSE; +} + +/* Process Address Reference + * Args: adract = Address Action (adacts) * + * symbol = Symbol to Process */ +void prcadr(int adract, char* symbol) { + DEBUG("Processing address '%s'\n", word) + strcpy(word,"#>("); + strcat(word,symbol); + strcat(word,")"); + if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } + else asmlin("LDY", word); + strcpy(word,"#<("); + strcat(word,symbol); + strcat(word,")"); + if (adract == ADPUSH) { asmlin("LDA", word); asmlin("PHA", ""); } + else asmlin("LDX", word); +} + +/* Parse and Compile Address of Operator * + * Args: adract = Address Action */ +void prsadr(int adract) { + DEBUG("expr.prsadr: Parsing address\n", 0) + if (isnpre()) prsnum(0xFFFF); + else { + getwrd(); + if (fndlab(word)) strcpy(value, word); + else prsvrw(FALSE, TRUE); + } + if (adract) prcadr(adract, value); //Compile Address Reference + else strcpy(word, value); //Save for Calling Routine +} + +/* Parse and Create Anonymous String * + * Args: adract = Address Action * + * alwstr = Allow String */ +void prsstr(int adract, int alwstr) { + if (!alwstr) ERROR("Illegal String Reference", 0, EXIT_FAILURE) + DEBUG("Parsing anonymous string\n", 0) + newlbl(vrname); //Generate Variable Name + value[0] = 0; //Use Variable Size 0 + setvar(MTNONE, VTCHAR); //Set Variable Name, Type, and Size + prsdts(); //Parse Data String + setdat(); //Set Variable Data + varcnt++; //Increment Variable Counter + if (adract) prcadr(adract, vrname); //Compile Address Reference + else strcpy(word, vrname); //Save for Calling Routine +} + +/* Check for and Process Address or String * + * Args: adract = Address Action * + * alwstr = Allow String */ +int chkadr(int adract, int alwstr) { + DEBUG("expr.chkadr: Checking for Address or String\n", 0) + int result = TRUE; + if (look('&')) prsadr(adract); + else if (match('"')) prsstr(adract, alwstr); + else result = FALSE; + skpspc(); + return result; +} + +/* Parse Byte Operator */ +void prsbop(void) { + char byteop = getnxt(); + CCMNT(byteop); + DEBUG("Parsing byte operator '%c'\n", byteop) + if (chkadr(FALSE, FALSE)) { + sprintf(value, "%c(%s)", byteop, word); + valtyp = LITERAL; + } else { + reqvar(FALSE); + if (vartyp != VTINT) ERROR("Integer Value Expected\n", 0, EXIT_FAILURE) + if (byteop == '>') strcat(value, "+1"); + vartyp = VTCHAR; + } + DEBUG("Set value to \"%s\"\n", value) +} + +/* Parse Function Argument or Return Values */ +void prsfpr(char trmntr) { + int pusha = 0; int pushy = 0; //A and Y Arguments Pushed + DEBUG("expr.prsfpr: Parsing Function Argument or Return Values\n", 0) + if (!chkadr(ADLDYX, TRUE) && isxpre() || match('.')) { + DEBUG("expr.prsfpr: Parsing Accumulator Expression\n", 0); + if (look('.')) pusha = 255; + else {if (prsxpf(0)) goto prsfne;} + if (look(',') && !chkadr(ADLDYX, TRUE)) { + if (look('.')) { + pushy = -1; + } + else { + if (look('(')) { + if (pusha==0) {pusha = 1; asmlin("PHA","");} //Save A on Stack + prsxpr(')'); asmlin("TAY", ""); //Evaluate Expression, and Copy to Y + } + else { + if (prstrm(TRUE)) goto prsfne; + asmlin("LDY", term); + } + } + if (look(',')) { + if (look('(')) { + if (pusha==0) {pusha = 1; asmlin("PHA","");} //Save A on Stack + if (pushy==0) {pushy = 1; asmlin("PHA",""); asmlin("PHY","");} //Save Y on Stack + prsxpr(')'); asmlin("TAX", ""); //Evaluate Expression, and Copy to X + } + else { + prsval(FALSE, TRUE); //Parse Value - Disallow Registers, Allow Constants + if (valtyp > VARIABLE) ERROR("Illegal Value Function Argument\n", 0, EXIT_FAILURE); + if (valtyp == VARIABLE && vartyp != VTCHAR) ERROR("Illegal Variable Type\n", 0, EXIT_FAILURE); + asmlin("LDX", value); + } + } + } + } + prsfne: + if (pushy==1) {asmlin("PLA",""); asmlin("TAY","");} //Pull Y Off Stack + if (pusha==1) asmlin("PLA",""); //Pull A Off Stack + expect(trmntr); +} + +/* Parse function call */ +void prsfnc(char trmntr) { + DEBUG("Processing Function Call '%s'\n", term) + //int argexp = FALSE; //Expression(s) in second and third argument + pshtrm(); //Push Function Name onto Term Stack + skpchr(); //skip open paren + CCMNT('('); + prsfpr(')'); //Parse Function Parameters + expect(trmntr); + poptrm(); //Pop Function Name off Term Stack + asmlin("JSR", term); + skpspc(); +} + +/* Process Integer Variable */ +void prcvri(void) { + DEBUG("Processing Integer Variable '%s'\n", value) + asmlin("LDX", value); + strcat(value, "+1"); + asmlin("LDY", value); +} + +/* Process Integer Variable in Term * + * Args: alwint = Allow Integer-Like Variable * + * Returns: Integer-Like Variable Processed - TRUE/FALSE */ +int prcivr(int alwint) { + switch (vartyp) { + case VTINT: + if (!alwint) ERROR("Illegal Use of Integer Variable %s\n", word, EXIT_FAILURE) + prcvri(); + return TRUE; + case VTARRAY: + if (!alwint) ERROR("Illegal Reference to Array %s\n", word, EXIT_FAILURE) + prcadr(ADNONE, term); + return TRUE; + case VTSTRUCT: + if (!alwint) ERROR("Illegal Reference to Struct %s\n", word, EXIT_FAILURE) + prcadr(ADNONE, term); + return TRUE; + default: + return FALSE; + } +} + +/* Process first term of expression */ +int prcftm(int alwint) { + DEBUG("Processing first term '%s'\n", value) + strcpy(term, value); + if (valtyp == VARIABLE && prcivr(alwint)) return TRUE; + if (valtyp == FUNCTION) prsfnc(0); //Parse Expression Function + else if (wordis("A")) return FALSE; + else if (wordis("X")) asmlin("TXA", ""); + else if (wordis("Y")) asmlin("TYA", ""); + else { chkidx(); asmlin("LDA", term); } + return FALSE; +} + +/* Parse first term of expession * + * First term can include function calls */ +int prsftm(int alwint) { + DEBUG("Parsing first term\n", 0) + if (match('*')) { + prcptr(); //Parse and Deference Pointer + asmlin("LDA", term); + return FALSE; + } + prsval(TRUE, TRUE); //Parse Value, Allow Registers & Constants + return prcftm(alwint); +} + +/* Process Arithmetic or Bitwise Operator * + * and the term that follows it */ +void prcopr(void) { + DEBUG("Processing operator '%c'\n", oper) + switch(oper) { + case '+': asmlin("CLC", ""); asmlin("ADC", term); break; //Addition + case '-': asmlin("SEC", ""); asmlin("SBC", term); break; //Subtraction + case '&': asmlin("AND", term); break; //Bitwise AND + case '!': //For systems that don't have pipe in character set + case '|': asmlin("ORA", term); break; //Bitwise OR + case '^': asmlin("EOR", term); break; //Bitwise XOR + default: ERROR("Unrecognized operator '%c'\n", oper, EXIT_FAILURE) + } + oper = 0; +} + +/* Parse Remainder of Expression */ +void prsrxp(char trmntr) { + skpspc(); + while (isoper()) { + trmcnt++; //Increment Expression Depth + prsopr(); //Parse Operator + prstrm(FALSE); //Parse Term + prcopr(); //Process Operator + trmcnt--; //Decrement Expression Depth + } + expect(trmntr); +} + +int prsxpp(char trmntr, int alwint) { + DEBUG("Parsing expression\n", 0) + skpspc(); + trmcnt = 0; //Initialize Expression Depth + if (match('-')) prcmns(); //Process Unary Minus + else if (prsftm(alwint)) return TRUE; //Parse First Term + prsrxp(trmntr); //Parse Remainder of Express + return FALSE; +} + +/* Parse and compile expression */ +void prsxpr(char trmntr) { + prsxpp(trmntr, FALSE); +} + +/* Parse and compile function parameter expression * + * Returns: TRUE if Integer Expression */ +int prsxpf(char trmntr) { + DEBUG("expr.prsxpf: Parsing Function Expression\n", 0) + return prsxpp(trmntr, TRUE); +} + +/* Parse and Compile Integer Expression * + * (Address, Integer Literal, Variable, * + * Struct Member, or Function) * + * Args: trmntr - expression terminator * + * asmxpr - assemble expression * + * Sets: value - Parsed Value or Symbol */ +void prsxpi(char trmntr, int asmxpr) { + skpspc(); + DEBUG("Parsing integer expression\n", 0) + if (!chkadr(TRUE, FALSE)) { + if (isnpre()) { + DEBUG("Parsing Integer Literal\n", 0) + int number = prsnum(0xFFFF); //Parse Number into value + if (asmxpr) { + sprintf(value, "#%d", number & 0xFF); asmlin("LDX", value); + sprintf(value, "#%d", number >> 8); asmlin("LDY", value); + } + } else if (isalph()) { + prsvar(FALSE, TRUE); + if (valtyp == FUNCTION) { + strcpy(term, value); + DEBUG("expr.prsxpi: Set term to %s\n", term) + prsfnc(0); //Parse Expression Function + } else if (valtyp == STRUCTURE) { + prsmbr(value); + if (vartyp != VTINT) ERROR("Illegal Member %s In Integer Expression", value, EXIT_FAILURE) + } else if (valtyp == VARIABLE && vartyp == VTINT) { + if (asmxpr) prcvri(); //Process Integer Variable + } else { + ERROR("Illegal Variable %s In Integer Expression", value, EXIT_FAILURE) + } + } else { + ERROR("Expected Integer Value or Function\n", 0, EXIT_FAILURE); + } + } + expect(trmntr); +} diff --git a/src/include.c b/src/include.c index 9e300db..0cd476c 100644 --- a/src/include.c +++ b/src/include.c @@ -177,7 +177,7 @@ void pincdr(void) { void phdwrd(void) { getwrd(); if (match(':')) prslab(); - else if (!ptype(MTNONE)) + else if (!pmodfr() && !ptype(MTNONE)) ERROR("Unexpected word '%s' in header\n", word, EXIT_FAILURE) } diff --git a/src/vars.c b/src/vars.c index b72812f..1090d3c 100644 --- a/src/vars.c +++ b/src/vars.c @@ -270,10 +270,12 @@ void addvar(int m, int t) { if (fndvar(vrname)) ERROR("Duplicate declaration of variable '%s\n", vrname, EXIT_FAILURE) if (t == VTVOID) ERROR("Illegal Variable Type\n", 0, EXIT_FAILURE) if (m & MTZP) { - setlbl(vrname); - sprintf(word, "$%hhX", zpaddr++); - if (t == VTINT) zpaddr++; //int uses two bytes - asmlin(EQUOP, word); + if (alcvar) { + setlbl(vrname); + sprintf(word, "$%hhX", zpaddr++); + if (t == VTINT) zpaddr++; //int uses two bytes + asmlin(EQUOP, word); + } strcpy(value, "*"); //Set Variable to Non Allocated } else if (m & MTALS) { diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..0180a21 --- /dev/null +++ b/test/README.md @@ -0,0 +1,27 @@ +C02 Test Directory Contents +=========================== + +Compile and Run Batch Files +--------------------------- + +| c02.bat | Compile .c02 file into .asm file | +| a02.bat | Assemble .asm file into .bin file | +| a1.bat | Compile/Assemble .c02 file to .asc Monitor Format | +| a2.bat | Compile/Assemble .c02 file to .dsk and run AppleWin | +| c64.bat | Compile/Assemble .c02 file to .prg and run x64 | +| o1.bat | Compile/Assemble .c02 file to .tap for Oricutron | +| orao.bat | Compile/Assemble .c02 file to .wav for Orao Emulator | +| p65.bat | Compile/Assemble .c02 file to .bin for py65m | +| v8k.bat | Compile/Assemble .c02 file to .prg and run xvic | +| x16.bat | Compile/Assemble .c02 file to .prg and run x16emu | + +C02 Test/Demo Programs +---------------------- + +| hello.c02 | Print "HELLO WORLD" using prtstr() | +| echo.c02 | Echo typed characters to screen | +| echohex.c02 | Display Hex Codes for types characters | +| conds.c02 | Test Conditional operators | +| loops.c02 | Test Loop and Conditional keywords | +| scrntst.c02 | Test module screen.h02 functions | +| sdeftest.c02 | Test module stddef.h02 functions | diff --git a/test/a02.bat b/test/a02.bat new file mode 100644 index 0000000..fe0619e --- /dev/null +++ b/test/a02.bat @@ -0,0 +1,14 @@ +@ECHO OFF +IF "%1" == "" ( + ECHO Usage: %0 a02file + GOTO :EXIT +) +SET ASMEXT="" +IF EXIST %1.a02 SET ASMEXT=a02 +IF EXIST %1.asm SET ASMEXT=asm +IF "%ASMEXT%" == "" ( + ECHO Assembly File %1 Not Found + GOTO :EXIT +) +ECHO Assembling File %1.%ASMEXT% +..\a02.exe %1.%ASMEXT% %1.bin %1.lst >%1.out diff --git a/test/a1.bat b/test/a1.bat index aff950d..a3e4d36 100644 --- a/test/a1.bat +++ b/test/a1.bat @@ -10,7 +10,7 @@ ECHO Compiling File %1.c02 IF ERRORLEVEL 1 EXIT /B ECHO Assembling File %1.asm -dasm %1.asm -f1 -o%1.obj -l%1.lst -s%1.sym +..\a02 -p %1.asm %1.obj %1.lst IF ERRORLEVEL 1 EXIT /B ECHO Converting Object File diff --git a/test/a2.bat b/test/a2.bat index 401bf18..8d57bfb 100644 --- a/test/a2.bat +++ b/test/a2.bat @@ -9,7 +9,7 @@ ECHO Compiling File %1.c02 IF ERRORLEVEL 1 EXIT /B ECHO Assembling File %1.asm -dasm %1.asm -f3 -o%1.obj -l%1.lst -s%1.sym +..\a02 %1.asm %1.obj %1.lst IF ERRORLEVEL 1 EXIT /B ECHO Building Disk Image diff --git a/test/c02.bat b/test/c02.bat new file mode 100644 index 0000000..6a515da --- /dev/null +++ b/test/c02.bat @@ -0,0 +1,10 @@ +@ECHO OFF +IF EXIST %1.c02 GOTO COMPILE + ECHO File %1.c02 not found + GOTO EOF + +:COMPILE +ECHO Compiling File %1.c02 +..\c02.exe -h header %1 >%1.dbg + +:EOF \ No newline at end of file diff --git a/test/c64.bat b/test/c64.bat index e76e61a..32f9d2c 100644 --- a/test/c64.bat +++ b/test/c64.bat @@ -1,18 +1,20 @@ +@REM Compile and Run C02 Program for C64 @ECHO OFF + IF EXIST %1.c02 GOTO COMPILE - ECHO File %1.c02 not found - GOTO EOF +ECHO File %1.c02 not found +GOTO EOF :COMPILE ECHO Compiling File %1.c02 for Commodore 64 -..\c02.exe -h c64 -s c64 -s cbm %1 >%1.dbg +..\c02.exe -d -h c64 -s c64 -s cbm %1 >%1.dbg IF %ERRORLEVEL% NEQ 0 GOTO EOF -ECHO Assembling File %1.asm -C:\Programs\dasm %1.asm -f1 -o%1.prg -l%1.lst -s%1.sym +ECHO Assembling File %1.asm +..\a02.exe -p %1.asm %1.prg %1.lst >%1.out IF %ERRORLEVEL% NEQ 0 GOTO EOF ECHO Starting Emulator -@start C:\Programs\WinVICE\x64.exe -config x64.ini %1.prg +start C:\Programs\WinVICE\x64.exe -config x64.ini %1.prg :EOF diff --git a/test/conds.c02 b/test/conds.c02 index 1515457..6652aec 100644 --- a/test/conds.c02 +++ b/test/conds.c02 @@ -3,65 +3,57 @@ ****************************************/ //Specify System Header using -H option -#include -#include -#include char allok; +void passed() {putstr(" PASS");} +void passln() {passed(); newlin();} +void failed() {putstr(" FAIL"); allok = $00;} +void failln() {failed(); newlin();} + main: -allok = #TRUE; + allok = $FF; //TRUE + + putstr("TEST CONDITIONALS"); newlin(); + + putstr(" 1<>1"); if (1<>1) failed(); else passed(); + putstr(" 1<>2"); if (1<>2) passln(); else failln(); + putstr(" 1==1"); if (1==1) passed(); else failed(); + putstr(" 1==2"); if (1==2) failln(); else passln(); + putstr("1+1=2"); if (1+1 == 2) passed(); else failed(); + putstr(" 2<1"); if (2<1) failln(); else passln(); + putstr(" 1<1"); if (1<1) failed(); else passed(); + putstr(" 1<2"); if (1<2) passln(); else failln(); + + putstr(" 1<=1"); if (1<=1) passed(); else failed(); + putstr(" 1<=2"); if (1<=2) passln(); else failln(); + putstr(" 2<=1"); if (2<=1) failed(); else passed(); + putstr(" 2>1"); if (2>1) passln(); else failln(); + putstr(" 1>1"); if (1>1) failed(); else passed(); + putstr(" 1>2"); if (1>2) failln(); else passln(); + putstr(" 1>=1"); if (1>=1) passed(); else failed(); + putstr(" 1>=2"); if (1>=2) failln(); else passln(); + putstr(" 2>=1"); if (2>=1) passed(); else failed(); + putstr(" !0:+"); if (!0:+) failln(); else passln(); + + putstr("$FF:+"); if ($FF:+) failed(); else passed(); + putstr(" $FF"); if ($FF) passln(); else failln(); + putstr("$FF:-"); if ($FF:-) passed(); else failed(); + putstr(" !$FF"); if (!$FF) failln(); else passln(); + putstr("$00:+"); if ($00:+) passed(); else failed(); + putstr(" $00"); if ($00) failln(); else passln(); + putstr("$00:-"); if ($00:-) failed(); else passed(); + putstr(" !$00"); if (!$00) passln(); else failln(); + + putstr(" 1!0"); if (1|0) passed(); else failed(); + putstr(" !1!0"); if (!1|0) failln(); else passln(); + putstr(" 1&0"); if (1&0) failed(); else passed(); + putstr(" !1&0"); if (!1&0) passln(); else failln(); + putstr(" 1^1"); if (1^1) failed(); else passed(); + putstr(" !1^1"); if (!1^1) passln(); else failln(); + + if (allok) putstr("ALL TESTS PASSED"); newlin(); + getchr(); + goto exit; -putln("Test Conditionals"); - -puts(" 1<>1"); if (1<>1) failed(); else passed(); -puts(" 1<>2"); if (1<>2) passln(); else failln(); -puts(" 1==1"); if (1==1) passed(); else failed(); -puts(" 1==2"); if (1==2) failln(); else passln(); -puts("1+1=2"); if (1+1 == 2) passed(); else failed(); -puts(" 2<1"); if (2<1) failln(); else passln(); -puts(" 1<1"); if (1<1) failed(); else passed(); -puts(" 1<2"); if (1<2) passln(); else failln(); - -puts(" 1<=1"); if (1<=1) passed(); else failed(); -puts(" 1<=2"); if (1<=2) passln(); else failln(); -puts(" 2<=1"); if (2<=1) failed(); else passed(); -puts(" 2>1"); if (2>1) passln(); else failln(); -puts(" 1>1"); if (1>1) failed(); else passed(); -puts(" 1>2"); if (1>2) failln(); else passln(); -puts(" 1>=1"); if (1>=1) passed(); else failed(); -puts(" 1>=2"); if (1>=2) failln(); else passln(); -puts(" 2>=1"); if (2>=1) passed(); else failed(); -puts(" !0:+"); if (!0:+) failln(); else passln(); - -puts("$FF:+"); if ($FF:+) failed(); else passed(); -puts(" $FF"); if ($FF) passln(); else failln(); -puts("$FF:-"); if ($FF:-) passed(); else failed(); -puts(" !$FF"); if (!$FF) failln(); else passln(); -puts("$00:+"); if ($00:+) passed(); else failed(); -puts(" $00"); if ($00) failln(); else passln(); -puts("$00:-"); if ($00:-) failed(); else passed(); -puts(" !$00"); if (!$00) passln(); else failln(); - -puts(" 1!0"); if (1|0) passed(); else failed(); -puts(" !1!0"); if (!1|0) failln(); else passln(); -puts(" 1&0"); if (1&0) failed(); else passed(); -puts(" !1&0"); if (!1&0) passln(); else failln(); -puts(" 1^1"); if (1^1) failed(); else passed(); -puts(" !1^1"); if (!1^1) passln(); else failln(); - -puts(" atoc(\"0\")"); if (atoc("0")) failln(); else passln(); -puts(" atoc(\"1\")"); if (atoc("1")) passln(); else failln(); -puts(" atoc(\"127\"):+"); if (atoc("127"):+) passln(); else failln(); -puts(" atoc(\"128\"):-"); if (atoc("128"):-) passln(); else failln(); - -if (allok) putln("All Tests Passed"); -getc(); - -goto exit; - -void passed() {puts(" Pass");} -void passln() {passed(); newlin();} -void failed() {puts(" Fail"); allok = #FALSE;} -void failln() {failed(); newlin();} diff --git a/test/echo.c02 b/test/echo.c02 index f38e4c9..19b33d0 100644 --- a/test/echo.c02 +++ b/test/echo.c02 @@ -11,6 +11,8 @@ char key; //Key value main: + putstr("TYPE KEYS TO ECHO"); newlin(); + putstr("ESCAPE/STOP TO END"); newlin(); while() { key = getchr(); select (key) { diff --git a/test/echohex.c02 b/test/echohex.c02 index 8a7b8f5..cce90b7 100644 --- a/test/echohex.c02 +++ b/test/echohex.c02 @@ -1,6 +1,7 @@ /******************************************************* * ECHOHEX - Test/Demo program for C02 Standard Header * * Displays ASCII Code of Typed Keys to Screen * + * RETURN/ENTER moves to new line * * ESCAPE/STOP key Ends Program * *******************************************************/ @@ -9,9 +10,12 @@ char key; //Key value main: + putstr("PRESS KEYS TO DISPLAY"); newlin(); + putstr("ESCAPE/STOP TO END"); newlin(); while() { key = getchr(); prbyte(key); putchr(' '); + if (key==#RTNKEY) newlin(); if (key==#ESCKEY) goto exit; } diff --git a/test/hello.c02 b/test/hello.c02 new file mode 100644 index 0000000..39f192f --- /dev/null +++ b/test/hello.c02 @@ -0,0 +1,12 @@ +/***************************************************** + * HELLO - Test/Demo program for C02 Standard Header * + * Prints "HELLO WORLD" and exits * + *****************************************************/ + +//Specify System Header using -H option + +main: + putstr("HELLO WORLD"); + newlin(); + goto exit; + diff --git a/test/ints.c02 b/test/ints.c02 new file mode 100644 index 0000000..d63f85f --- /dev/null +++ b/test/ints.c02 @@ -0,0 +1,87 @@ +/**************************************************** + * INTS - Test Integer Variables and Function Calls */ + +//Specify System Header using -H option +#include +#include +#include +#include +#include +#include +#include +#include + +char n; //Number of Characters +char r[255]; //Test Array +char s[128]; //Test String +const char istr = "9876"; +const char t = "CONST STRING."; + +alias int nmi = $FFFA; //NMI Vector +alias int rst = $FFFC; //Reset Vector +alias int brk = $FFFE; //Break Vector + +int addr; //Various Addresses +int eoj; //End of Job + +const int less = $789A; +const int more = $BCDE; + +int yx, dd; //Function Arguments and Variables +char aa, xx, yy; + +struct record {char name[8], index; int addr;}; +struct record rec; + +main: + +eoj = getend(); + +setdst(&rec.name); strcpy("FRED"); +rec.index = $AB; +rec.addr = $CDEF; + +newlin(); + +/* Print Vector Contents */ +setdst(nmi); printf("NMI=$%w%n"); +setdst(rst); printf("RST=$%w%n"); +setdst(brk); printf("BRK=$%w%n%n"); + +/* Print Contents of EOJ */ +setdst(eoj); printf("EOJ=$%w%n%n"); + +anykey(); + +/* Test Function Call Arguments */ +putln("ADDR=49152"); addr = 49152; setdst(&49152); cmpdst(addr); +putln("ADDR=&T"); addr = &t; setdst(t); cmpdst(addr); +putln("ADDR=&REC"); addr = &rec; setdst(&rec); cmpdst(addr); +putln("ADDR=&REC.NAME"); addr = &rec.name; setdst(&rec.name); cmpdst(addr); +putln("ADDR=&REC.INDEX"); addr = &rec.index; setdst(&rec.index); cmpdst(addr); +putln("ADDR=&REC.ADDR"); addr = &rec.addr; setdst(&rec.addr); cmpdst(addr); + +anykey(); + +puts("GOTO (EOJ)"); +goto (eoj); + failln(); + goto exit; +end: + passln(); + goto exit; + +int getend() { + return &end; +} + +void prtwrd(., yy, xx) { + putchr('$'); puthex(yy); puthex(xx); +} + +void cmpdst(yx) { + dd = getdst(); + prtwrd(yx); putchr('='); prtwrd(dd); + if (>yx == >dd and + +char key; //Key value + +main: + putstr("PRESS KEYS TO SEE DEFINITIONS"); newlin(); + while() { + key = getchr(); + if (!key) continue; + select (key) { + case #KEYBCK: putstr("BACKSPACE"); + case #KEYBRK: putstr("BREAK"); + case #KEYCLR: putstr("CLEAR"); + case #KEYCPY: putstr("COPY"); + case #KEYDEL: putstr("DELETE"); + case #KEYDN : putstr("DOWN"); + case #KEYESC: putstr("ESCAPE"); + case #KEYFN1: putstr("F1"); + case #KEYFN2: putstr("F2"); + case #KEYFN3: putstr("F3"); + case #KEYFN4: putstr("F4"); + case #KEYFN5: putstr("F5"); + case #KEYFN6: putstr("F6"); + case #KEYFN7: putstr("F7"); + case #KEYFN8: putstr("F8"); + case #KEYFN9: putstr("F9"); + case #KEYFNA: putstr("F10"); + case #KEYFNB: putstr("F11"); + case #KEYFNC: putstr("F12"); + case #KEYHLP: putstr("HELP"); + case #KEYHOM: putstr("HOME"); + case #KEYINS: putstr("INSERT"); + case #KEYLFT: putstr("LEFT"); + case #KEYRGT: putstr("RIGHT"); + case #KEYRTN: putstr("RETURN"); + case #KEYRTS: putstr("SHIFT-RETURN"); + case #KEYRUN: putstr("RUN"); + case #KEYRVF: putstr("RVS-OFF"); + case #KEYRVS: putstr("RVS-ON"); + case #KEYSPS: putstr("SHIFT-SPACE"); + case #KEYTAB: putstr("TAB"); + case #KEYTAS: putstr("SHIFT-TAB"); + case #KEYUP : putstr("UP"); + case ' ': putstr("SPACE"); + default: if (key > ' ' and key <> #DELKEY) putchr(key); + } + putstr(" ["); prbyte(key); putstr("] "); + if (key == #ESCKEY) break; + } + goto exit; diff --git a/test/loops.c02 b/test/loops.c02 index 69350dc..222801f 100644 --- a/test/loops.c02 +++ b/test/loops.c02 @@ -6,118 +6,115 @@ #include #include -char i, b; -const char failed = " Test Failed!"; +char aa,ii; //Function Variables +char b; //Comparison Variable +char i; //Loop Counter + +void putlin() {putstr(); newlin();} +void failed() {putlin(" FAILED");} +void passed() {putlin(" PASSED");} main: + putlin("TESTING LOOPS"); -/* Test If/Goto Loop */ -puts("IF "); -i = 0; -ifloop: - prbyte(i); - putc(' '); - i++; - if (i < 10) goto ifloop; -newlin(); + /* Test If/Goto Loop */ + putstr("IF "); + i = 0; + ifloop: + putchr('0'+i); + i++; + if (i < 8) goto ifloop; + if (i=8) passed(); else failed(); -/* Test While Loop */ -puts("WHILE "); -i = 0; -while (i < 10) { - prbyte(i); - putc(' '); - i++; -} -newlin(); + /* Test Block If */ + putstr("BLOCK "); + b = 1; + if (b>0) { + prhex(b); + putstr(" > "); + prhex(0); + passed(); + } + else failed(); -/* Test Do Loop */ -puts("DO "); -i = 0; -do { - prbyte(i); - putc(' '); - i++; -} while (i<10); -newlin(); + putstr(" IF "); + b = 0; + if (b>0) failed(); + else { + putchr('0'+i); + putstr(" = "); + prhex(0); + passed(); + } -/* Test For Loop */ -puts("FOR "); -i = 0; -for (i=0;i<10;i++) { - prbyte(i); - putc(' '); -} -newlin(); + /* Test While Loop */ + putstr("WHILE "); + i = 0; + while (i < 8) { + putchr('0'+i); + i++; + } + if (i=8) passed(); else failed(); -/* While with Break */ -puts("BREAK "); -i = 0; -while ($FF) { - if (i = 10) break; - prbyte(i); - putc(' '); - i++; -} -newlin(); + /* Test Do Loop */ + putstr("DO "); + i = 0; + do { + putchr('0'+i); + i++; + } while (i<8); + if (i=8) passed(); else failed(); -/* For with Continue */ -puts("CONT "); -for (i=0;i<10;i++) { - if (i & 1) continue; - prbyte(i); - putc(' '); -} -newlin(); + /* Test For Loop */ + putstr("FOR "); + i = 0; + for (i=0;i<8;i++) { + putchr('0'+i); + } + if (i=8) passed(); else failed(); + + /* While with Break */ + putstr("BREAK "); + i = 0; + while ($FF) { + if (i = 8) break; + putchr('0'+i); + i++; + } + if (i=8) passed(); else failed(); + + /* For with Continue */ + putstr("CONT "); + for (i=0;i<16;i++) { + if (i & 1) { continue; i=$FF;} + putchr('A'+i); + } + if (i=16) passed(); else failed(); /* Test Do with Break and Continue*/ -i = 0; -puts("DO BC "); -do { - i++; - if (!i&1) continue; - if (i>15) break; - prbyte(i); - putc(' '); -} while ($FF); -newlin(); + i = 0; + putstr("DO BC "); + do { + i++; + if (!i&1) {continue; i=$FF;} + if (i>16) break; + putchr('A'+i); + } while ($FF); + if (i=17) passed(); else failed(); - -newlin(); - -/* Test Block If */ -putln("BLOCK IF"); -b = 1; -if (b>0) { - prbyte(b); - puts(" is greater than "); - prbyte(0); - newlin(); -} -else - putln(&failed); -b = 0; -if (b>0) { - putln(&failed); -} -else { - prbyte(b); - puts(" is equal to "); - prbyte(0); - newlin(); -} -newlin(); - -/* Test If/Else in For Loop */ -putln("FOR/IF/ELSE"); -for(i = 0;i<4;i++) { - prbyte(i); - if (i & 1) - putln(" is odd"); - else - putln(" is even"); -} -newlin(); - - -goto exit; + /* Test If/Else, Select in For Loop */ + for(i = 0;i<4;i++) { + select (i) { + case 0: putstr("FOR "); b=0; + case 1: putstr(" IF "); b=1; + case 2: putstr(" ELSE "); b=2; + case 3: putstr(" SELECT "); b=3; + default: putstr(" ERROR! "); b=$FF; + } + putchr('0'+i); + if (i & 1) putstr("-ODD "); else putstr("-EVEN"); + if (i=b) passed(); else failed(); + } + + putlin("ALL TESTS COMPLETE"); + goto exit; diff --git a/test/orao.bat b/test/orao.bat new file mode 100644 index 0000000..80157c6 --- /dev/null +++ b/test/orao.bat @@ -0,0 +1,35 @@ +@REM Compile and Assemble Program for Orao +@ECHO OFF + +SET ORAOBIN=C:\Programs\OraoEmulator\bin +SET ORAOTAP=C:\Programs\OraoEmulator\tap +SET ORAOWAV=C:\Programs\OraoPy\wav +SET ORAOTOOLS=C:\Programs\OraoEmulator\tools + +IF EXIST %1.c02 GOTO COMPILE + ECHO File %1.c02 not found + EXIT /B + +:COMPILE +ECHO Compiling File %1.c02 +..\c02.exe -h orao -s orao %1 >%1.dbg +IF ERRORLEVEL 1 EXIT /B + +ECHO Assembling File %1.asm +dasm %1.asm -f1 -o%1.obj -l%1.lst -s%1.sym +IF ERRORLEVEL 1 EXIT /B + +ECHO Creating Binary File +%ORAOTOOLS%\obj2bin %1.obj %ORAOBIN%\%1.bin +IF ERRORLEVEL 1 EXIT /B + +ECHO Building Tape Image +%ORAOTOOLS%\maketap %ORAOTAP%\%1.tap %ORAOBIN%\%1.bin +IF ERRORLEVEL 1 EXIT /B + +ECHO Building WAV File +%ORAOTOOLS%\orao2wav %ORAOBIN%\%1.bin +IF ERRORLEVEL 1 EXIT /B +MOVE %ORAOBIN%\%1.wav %ORAOWAV% + +DEL %1.obj diff --git a/test/scrntst.c02 b/test/scrntst.c02 new file mode 100644 index 0000000..5b3887f --- /dev/null +++ b/test/scrntst.c02 @@ -0,0 +1,71 @@ +/************************************ + * SCRNTST - Test C02 screen module * + ************************************/ + +//use -h amd -s options on command line +#include + +char col, row, wdth, hght; +char mode, modex; +char a, c, f, i, m; +char aa, yy; + +const char modes = {#SMTEXT, #SMWIDE}; + +void prtaxy(aa,yy) { + if (aa & $F0) prbyte(aa); else prhex(aa); + putchr('X'); + if (yy & $F0) prbyte(yy); else prhex(yy); +} + +void putlin() {putstr(); newlin();} + +main: + + for (modex=0; modex<@modes; modex++) { + + mode = modes[modex]; + if (mode == $FF) continue; //Unsupported Mode + + if (setscr(mode)=$FF) putlin("ERROR IN SETSCR()"); + m = getscr(); + if (m <> mode) putlin("ERROR IN GETSCR()"); + putstr("MODE="); prbyte(m); newlin(); + + wdth, hght = getsiz(); //Get Screen Width & Height + prtaxy(wdth,hght); newlin(); + + for (i=1; i<6; i++) putchr('.'); + col, row = getpos(); //Get Cursor Position + prtaxy(col,row); + crsrhm(); prtaxy(getpos()); + getchr(); newlin(); //Wait For keypress + + clrscr(); //Clear Screen + col, row = getpos(); //Get Cursor Position + prtaxy(col, row); + f = (col == 255) ? 0 : $FF; + getchr(); + + if (f) clrscr(); else newlin(); + + if (wdth:- or hght:-) goto exit; + for (c='@'; c<'`'; c++) { + if (!f) newlin(); + for (row=hght-2; row; row--) { + if (!f) putchr(' '); + for (col=wdth-2; col; col--) { + if (f) setpos(col,row); + putchr(c); + } + if (!f) newlin(); + if (getkey() == #ESCKEY) goto exit; + } + if (!f) getchr(); + } + if (f) getchr(); //Wait For keypress + newlin(); + + } //for modex + + goto exit; diff --git a/test/sdeftest.c02 b/test/sdeftest.c02 new file mode 100644 index 0000000..e5c1696 --- /dev/null +++ b/test/sdeftest.c02 @@ -0,0 +1,80 @@ +/************************************** + * SDEFTEST - Test Library stddef.h02 * + **************************************/ + +//use -h option on command line +#include + +char lo,hi; +char aa,hh,ll,xx,yy; +int dstadr,srcadr; + +void clrdst() {dstlo=0; dsthi=0;} +void clrreg() {return 0,0,0;} +void clrtmp() {temp0=0; temp1=0; temp2=0; temp3=0;} +void clrsrc() {srclo=0; srchi=0;} +void prskey() {putstr(" PRESS ANY KEY"); newlin(); getchr(); newlin();} +void prtcma(aa) {putchr(','); prbyte(aa);} +void prtdhl() {ll=dstlo; hh=dsthi; putstr(" DSTHI,LO="); prbyte(hh); prtcma(ll); newlin();} +void prtdst() {prbyte(dsthi);prbyte(dstlo); newlin();} +void prtlin() {putstr(); newlin();} +void prtreg(aa,yy,xx) {putstr(" A,X,Y="); prbyte(aa); prtcma(yy); prtcma(xx); newlin();} +void prtsav() {putstr(" TEMP1,2="); prtcma(temp1); prtcma(temp2); newlin();} +void prtshl() {ll=srclo; hh=srchi; putstr(" SRCHI,LO="); prbyte(hh); prtcma(ll); newlin();} +void prtsrc() {prbyte(srchi);prbyte(srclo); newlin();} +void prttmp() {putstr(" TEMP0,1,2="); prbyte(temp0); prtcma(temp1); prtcma(temp2); newlin();} +void prtwrd(.,yy,xx) {prbyte(yy); prbyte(xx); newlin();} +void setreg(aa,yy,xx) {} + +main: + newlin(); + + putstr("#TRUE="); prbyte(#TRUE); + putstr(", #FALSE="); prbyte(#FALSE); newlin(); + newlin(); + + prtlin("SAVREG($A,$B,$C)"); clrtmp(); savreg($A,$B,$C); prttmp(); + prtlin("RESREG()"); clrreg(); prtreg(resreg()); + prtlin("SAVRXY($D,$E,$F)"); clrtmp(); savrxy($D,$E,$F); prttmp(); + prtlin("RESRXY()"); clrreg(); prtreg(resrxy()); + newlin(); + + prtlin("SAVRXY(&$1234)"); putstr(" ADDTXY(&$5678)=$"); + savrxy(&$1234); prtwrd(addtxy(&$5678)); + prtlin("SAVRXY(&$1234)"); putstr(" SUBTXY(&$68AC)=$"); + savrxy(&$1234); prtwrd(subtxy(&$68AC)); + newlin(); + + putstr("DECRXY(&$0000)=$"); prtwrd(decrxy(&$0000)); + putstr("INCRXY(&$FFFF)=$"); prtwrd(incrxy(&$FFFF)); + newlin(); + + prskey(); + + prtlin("SETSRC(&$1234)"); clrsrc(); setsrc(&$1234); savsrc(); + prtshl(); prtlin("SAVSRC()"); prtsav(); + prtlin("RESSRC()"); clrsrc(); ressrc(); srcadr=getsrc(); + prtshl(); putstr("GETSRC()="); prtwrd(srcadr); + prtlin("SETDSS()"); clrdst(); ressrc(); setdss(); prtdhl(); + newlin(); + + prtlin("SETDST(&$5678)"); clrdst(); setdst(&$5678);savdst(); + prtdhl(); prtlin("SAVDST()"); prtsav(); + prtlin("RESDST()"); clrdst(); resdst(); dstadr=getdst(); + prtdhl(); putstr("GETSRC()="); prtwrd(dstadr); + prtlin("SETSRD()"); clrsrc(); resdst(); setsrd(); prtshl(); + newlin(); + + prskey(); + + prtlin("SETSRC(&$0FFF)"); putstr(" ADDSRA($FF)=$"); + setsrc(&$0FFF); addsra($FF); prtsrc(); + prtlin("SETSRC(&$1234)"); putstr(" ADDSRC(&$CDEF)=$"); + setsrc(&$1234); addsrc(&$CDEF); prtsrc(); + prtlin("SETDST(&$0FFF)"); putstr(" ADDDSA($FF)=$"); + setdst(&$0FFF); adddsa($FF); prtdst(); + prtlin("SETDST(&$1234)"); putstr(" ADDDST(&$CDEF)=$"); + setdst(&$1234); adddst(&$CDEF); prtdst(); + newlin(); + + goto exit; diff --git a/test/slibtest.c02 b/test/slibtest.c02 new file mode 100644 index 0000000..e44d91d --- /dev/null +++ b/test/slibtest.c02 @@ -0,0 +1,231 @@ +/************************************************** + * TESTSLIB - Test Library stdlib.h02 for py65mon * + **************************************************/ + +//Specify System Header using -H option +#include +#include + +char aa, yy, xx; + +void prtcma(aa) {putchr(','); prbyte(aa);} +void prtlin() {putstr(); newlin();} +void prtok() {prtlin(" OK");} +void prtopr(aa,yy,xx) {prbyte(aa); putchr(yy); prbyte(xx); putchr("=");} + +main: + +tstabs: //Test abs() +char onum, anum, cnum; + + putstr("ABS()"); + onum = 0; + do { //test abs() positive numbers + anum = abs(onum); + if (onum <> anum) goto abserr; + onum++; + } while (onum < $80); + do { //test abs() negative numbers + anum = abs(onum); + cnum = -onum; + if (anum <> cnum) goto abserr; + onum++; + } while (onum); + prtok(); + +tstmnx: //Test min() and max() +char lnum, rnum, nnum, xnum; + + putstr("MAX(), MIN()"); + lnum = 0; do { + rnum = 0; do { + xnum = max(lnum,rnum); + nnum = min(lnum,rnum); + if (lnum > rnum) { + if (xnum <> lnum) maxerr(); + if (nnum <> rnum) minerr(); + } else { + if (xnum <> rnum) maxerr(); + if (nnum <> lnum) minerr(); + } + } while (rnum); + } while (lnum); + prtok(); + +tstmlt: //Test mult() +char mltplr, mltpnd, acmlsb, acmmsb, acmlst; +char prodct, ovrflw; + + putstr("MULT()"); + mltplr = 1; + do { + if (!mltplr & $F) putchr('.'); + mltpnd = 1; acmlst = 0; + acmlsb = 0; acmmsb = 0; + do { + acmlsb = acmlsb + mltplr; + if (acmlsb acmlsb) goto mlterr; + mltpnd++; + } while (mltpnd); + mltplr++; + } while (mltplr); + prtok(); + +tstdiv: //Test div() +char maxmpd, divdnd, divisr, quotnt; + +putstr("DIV()"); +mltplr = 255; +maxmpd = 1; +drloop: + mltpnd = 1; + acmlsb = 0; + ddloop: + acmlsb = acmlsb + mltplr; + prodct = mult(mltplr, mltpnd); + quotnt = div(prodct, mltpnd); + if (quotnt <> mltplr) goto derror; + mltpnd++; + if (mltpnd < maxmpd) goto ddloop; + mltplr>>; + maxmpd<<; + if (mltplr <> 0) goto drloop; + prtok(); + +tstrnd: //Test rand() and rands() +char countr, rndnum, rndtbl[255]; + + putstr("RAND()"); + rands(1); //Seed Random Number Generator; + + countr = 0; + + riloop: + rndtbl[countr] = 0; + countr++; + if (countr <> 0) goto riloop; + + rnloop: + rndnum = rand(); + if (rndtbl[rndnum] > 0) goto rnderr; + rndtbl[rndnum] = $FF; + countr++; + if (countr < 255) goto rnloop; + prtok(); + +tstros: //Test rotatl(), rotatr(), swap() +char lbyte, rbyte, obyte, sbyte, tbyte, scount; + + putstr("ROTATL(), SHIFTL()"); + obyte = 0; + do { + if (!obyte & $F) putchr('.'); + scount = 0; sbyte = obyte; tbyte = obyte; + do { + rbyte = rotatl(obyte, scount); if (rbyte <> tbyte) goto rtlerr; + lbyte = shiftl(obyte, scount); if (lbyte <> sbyte) goto shlerr; + sbyte<<; + temp0 = tbyte; tbyte<<; if (temp0:-) tbyte++; + scount++; if (scount == 8) scount = $F8; + } while (scount); + obyte ++; + } while (obyte); + prtok(); + + putstr("ROTATR(), SHIFTR()"); + obyte = 0; + do { + if (!obyte & $F) putchr('.'); + scount = 0; sbyte = obyte; tbyte = obyte; + do { + rbyte = rotatr(obyte, scount); if (rbyte <> tbyte) goto rtrerr; + lbyte = shiftr(obyte, scount); if (lbyte <> sbyte) goto shrerr; + sbyte>>; + temp0 = tbyte; tbyte>>; if (temp0 & 1) tbyte = tbyte | $80; + scount++; if (scount == 8) scount = $F8; + } while (scount); + obyte ++; + } while (obyte); + prtok(); + + putstr("SWAP()"); + lbyte=0; do { + rbyte = 0; do { + obyte = lbyte & $f0; obyte = rbyte & $0f + lbyte; + tbyte = lbyte & $0f; tbyte = rbyte & $f0 + lbyte; + sbyte = swap(obyte); + if (sbyte <> tbyte) goto swperr; + rbyte = rbyte + $11; + } while (rbyte & $0f); + } while (lbyte & $0f); + prtok(); + +tstc2a: //Test ctoa(); +char srcchr, dstchr, tststr[4]; + + putstr("ATOC(), CTOA()"); + srcchr = 0; do { + ctoa(srcchr, &tststr); + dstchr = atoc(&tststr); + if (srcchr <> dstchr) goto c2aerr; + srcchr++; + } while (srcchr); + prtok(); + +goto exit; + +abserr: + putstr("ABS("); prbyte(onum); putstr(")="); prbyte(anum); prtcma(cnum); newlin(); + goto exit; + +maxerr: + putstr("MAX("); prbyte(lnum); prtcma(rnum); putstr(")="); prbyte(xnum); newlin(); + goto exit; + +minerr: + putstr("MIN("); prbyte(lnum); prtcma(rnum); putstr(")="); prbyte(nnum); newlin(); + goto exit; + +mlterr: + newlin(); prtopr(mltplr,'*',mltpnd); prbyte(prodct); prtcma(acmlsb); newlin(); + goto exit; + +derror: + newlin(); prtopr(divdnd,'/',divisr); prbyte(quotnt); prtcma(mltplr); newlin(); + goto exit; + +rnderr: + newlin(); putstr("RAND()="); prbyte(rndnum); prtcma(countr); newlin(); + goto exit; + +rtlerr: + newlin(); putstr("ROTATL("); prbyte(obyte); prtcma(scount); putstr(")="); + prbyte(rbyte); prtcma(tbyte); newlin(); + goto exit; + +rtrerr: + newlin(); putstr("ROTATR("); prbyte(obyte); prtcma(scount); putstr(")="); + prbyte(rbyte); prtcma(tbyte); newlin(); + goto exit; + +shlerr: + newlin(); putstr("SHIFTL("); prbyte(obyte); prtcma(scount); putstr(")="); + prbyte(lbyte); prtcma(sbyte); newlin(); + goto exit; + +shrerr: + newlin(); putstr("SHIFTR("); prbyte(obyte); prtcma(scount); putstr(")="); + prbyte(lbyte); prtcma(sbyte); newlin(); + goto exit; + +swperr: + newlin(); putstr("SWAP("); prbyte(obyte); putstr(")="); + prbyte(sbyte); prtcma(tbyte); newlin(); + goto exit; + +c2aerr: + putstr("CTOA("); prbyte(srcchr); putstr(")="); prbyte(dstchr); newlin(); + goto exit; diff --git a/test/testilib.c02 b/test/testilib.c02 new file mode 100644 index 0000000..d002bc1 --- /dev/null +++ b/test/testilib.c02 @@ -0,0 +1,105 @@ +/**************************************************** + * INTS - Test Integer Variables and Function Calls */ + +//Specify System Header using -H option +#include +#include +#include +#include +#include +#include +#include +#include + +char size; +char s[128]; //Test String + +int ivar,ival; //Integer Variables +int icmp,itot,ires; //Function Variables +int less, more; //Test Values for imin() and imax() + +int yx, dd; //Function Arguments and Variables + +void cpival(icmp) { + if (>ival <> >icmp or "); putwrd(icmp); + failln(); + goto exit; + } +} + +/* Test imin() and imax() */ +void minmax() { + newlin(); + puts("LESS=$"); putwrd(less); puts(",MORE=$"); putwrd(more); newlin(); + puts(" IMIN()=$"); setsrc(less); + ival = imin(more); putwrd(ival); newlin(); + cpival(less); + puts(" IMAX()=$"); setsrc(less); + ival = imax(more); putwrd(ival); newlin(); + cpival(more); +} + +/* Test cvibcd() and upbcdi() */ +void intbcd(ival) { + newlin(); puts("CVIBCD($"); putwrd(ival); puts(")=$"); + cvibcd(ival); puthex(temp2); puthex(temp1); puthex(temp0); +} + +/* Test itoa() and atoi() */ +void itaati(ivar) { + newlin(); + puts("ITOA($"); putwrd(ivar); puts(")=\""); + setdst(s); size = itoa(ivar); puts(s); putln("\""); + puts("ATOI(\""); puts(s); puts("\")=$"); + ival = atoi(s); putwrd(ival); newlin(); + //cpival(ivar); +} + +/* Test iadd() and isub() */ +void addsub(ivar) { + newlin(); + putint(ival); putchr('+'); putint(ivar); putchr('='); + setsrc(ival); itot = iadd(ivar); putint(itot); newlin(); + putint(itot); putchr('-'); putint(ivar); putchr('='); + setsrc(itot); ires = isub(ivar); putint(ires); newlin(); + cpival(ires); +} + +/* Test imult() and idiv() */ +void mltdiv(ivar) { + newlin(); + putint(ival); putchr('X'); putint(ivar); putchr('='); + setsrc(ival); itot = imult(ivar); putint(itot); newlin(); + putint(itot); putchr('/'); putint(ivar); putchr('='); + setsrc(itot); ires = idiv(ivar); putint(ires); newlin(); + cpival(ires); +} + +main: + +less = $009A; more = $00DE; minmax(); +less = $789A; more = $78DE; minmax(); +less = $7800; more = $BC00; minmax(); +less = $789A; more = $BCDE; minmax(); +anykey(); + +itaati(&0); +itaati(&234); +itaati(&256); +itaati(&456); +itaati(&23456); +itaati(&$FFFF); +anykey(); + +ival = &23; addsub(&34); +ival = &1234; addsub(&5678); +ival = &23456; addsub(&34567); +ival = &$7700; addsub(&$6600); +ival = &$7FFF; addsub(&$8000); +anykey(); + +//ival = &123; mltdiv(&234); + + +goto exit; \ No newline at end of file diff --git a/test/testscrn.c02 b/test/testscrn.c02 deleted file mode 100644 index 5820dd2..0000000 --- a/test/testscrn.c02 +++ /dev/null @@ -1,53 +0,0 @@ -/************************************ - * TESTHDR - Test C02 screen module * - ************************************/ - -//use -h amd -s options on command line -#include - -char col, row, wdth, hght; -char c, f, i, aa, yy; - -void prtaxy(aa,yy) { - if (aa & $F0) prbyte(aa); else prhex(aa); - putchr('X'); - if (yy & $F0) prbyte(yy); else prhex(yy); -} - -main: - - wdth, hght = getsiz(); //Get Screen Width & Height - prtaxy(wdth,hght); newlin(); - - for (i=1; i<6; i++) putchr('.'); - col, row = getpos(); //Get Cursor Position - prtaxy(col,row); - crsrhm(); prtaxy(getpos()); - getchr(); newlin(); //Wait For keypress - - clrscr(); //Clear Screen - col, row = getpos(); //Get Cursor Position - prtaxy(col, row); - f = (col == 255) ? 0 : $FF; - getchr(); - - if (f) clrscr(); else newlin(); - - if (wdth:- or hght:-) goto exit; - for (c='@'; c<'`'; c++) { - if (!f) newlin(); - for (row=hght-2; row; row--) { - if (!f) putchr(' '); - for (col=wdth-2; col; col--) { - if (f) setpos(col,row); - putchr(c); - } - if (!f) newlin(); - if (getkey() == #ESCKEY) goto exit; - } - if (!f) getchr(); - } - if (f) getchr(); //Wait For keypress - newlin(); - -goto exit; diff --git a/test/testsd.c02 b/test/testsd.c02 deleted file mode 100644 index 42e4a69..0000000 --- a/test/testsd.c02 +++ /dev/null @@ -1,82 +0,0 @@ -/************************************************ - * TESTSD - Test Library stddef.h02 for py65mon * - ************************************************/ - - -//use -h option on command line -#include - -const char txtstr = { - "#TRUE=",", #FALSE=", - "SAVREG($A,$B,$C)", " TEMP0,1,2=", - "RESREG()", " A,X,Y=", - "SETSRC(&$1234)"," SRCLO,HI=", " GETSRC()=", - "SETDST(&$5678)"," DSTLO,HI=", " GETDST()=" - }; -char txtidx; - -char aa,xx,yy; - -main: - txtidx = 0; - newlin(); - - prttxt(); prbyte(#TRUE); - prttxt(); prbyte(#FALSE); - newlin(); newlin(); - - temp0=0; temp1=0; temp3 = 0; - prtlin(); savreg($A,$B,$C); - prttxt(); prbyte(temp0); - prtcma(); prbyte(temp1); - prtcma(); prbyte(temp2); - newlin(); - - setreg(0,0,0); - prtlin(); aa,yy,xx = resreg(); - prttxt(); prbyte(aa); - prtcma(); prbyte(yy); - prtcma(); prbyte(xx); - newlin(); newlin(); - - - srclo = 0; srchi = 0; - prtlin(); setsrc(&$1234); - prttxt(); prbyte(srclo); - prtcma(); prbyte(srchi); - newlin(); - prttxt(); setreg(0,0,0); - getsrc(); prtwrd(); - newlin(); newlin(); - - dstlo = 0; dsthi = 0; - prtlin(); setdst(&$5678); - prttxt(); prbyte(dstlo); - prtcma(); prbyte(dsthi); - newlin(); - prttxt(); setreg(0,0,0); - getdst(); prtwrd(); - newlin(); newlin(); - - -goto exit; - -void setreg(aa,yy,xx) {} - -void prtwrd(aa,yy,xx) { - prbyte(yy); - prbyte(xx); -} - -void prtcma() {prchr(',');} - -void prtlin() {prttxt(); newlin();} - -void prttxt() { - while (txtstr[txtidx]) { - //prbyte(txtidx);prchr(' '); - prchr(txtstr[txtidx]); - txtidx++; - } - txtidx++; -} diff --git a/test/testsl.c02 b/test/testsl.c02 deleted file mode 100644 index 5a64c42..0000000 --- a/test/testsl.c02 +++ /dev/null @@ -1,220 +0,0 @@ -/************************************************ - * TESTSL - Test Library stdlib.h02 for py65mon * - ************************************************/ - -//Specify System Header using -H option -#include -#include - -main: - -tstabs: //Test abs() -char onum, anum, cnum; - -prchr('A'); -prchr('B'); -prchr('S'); -prchr(' '); - -//test abs() positive numbers -onum = 0; -aploop: - anum = abs(onum); - if (onum <> anum) goto abserr; - onum++; - if (onum < $80) goto aploop; - -//test abs() negative numbers -anloop: - anum = abs(onum); - cnum = -onum; - if (anum <> cnum) goto abserr; - onum++; - if (onum > $00) goto anloop; - prchr('O'); - prchr('K'); - newlin(); - -tstmlt: //Test mult() -char mltplr, mltpnd, acmlsb, acmmsb, acmlst; -char prodct, ovrflw; - -mltplr = 1; -mrloop: - prbyte(mltplr); - mltpnd = 1; acmlst = 0; - acmlsb = 0; acmmsb = 0; - mdloop: - acmlsb = acmlsb + mltplr; - if (acmlsb acmlsb) goto merror; - //if (ovrflw <> acmmsb) goto merror; - mltpnd++; - if (mltpnd > 0) goto mdloop; - mltplr++; - if (mltplr > 0) goto mrloop; - newlin(); - prchr('M'); - prchr('U'); - prchr('L'); - prchr('T'); - prchr(' '); - prchr('O'); - prchr('K'); - newlin(); - -tstdiv: //Test div() -char maxmpd, divdnd, divisr, quotnt; - -mltplr = 255; -maxmpd = 1; -drloop: - prbyte(mltplr); - mltpnd = 1; - acmlsb = 0; - ddloop: - prbyte(mltpnd); - acmlsb = acmlsb + mltplr; - prodct = mult(mltplr, mltpnd); - quotnt = div(prodct, mltpnd); - if (quotnt <> mltplr) goto derror; - mltpnd++; - if (mltpnd < maxmpd) goto ddloop; - newlin(); - mltplr>>; - maxmpd<<; - if (mltplr <> 0) goto drloop; - newlin(); - prchr('D'); - prchr('I'); - prchr('V'); - prchr(' '); - prchr('O'); - prchr('K'); - newlin(); - - -tstrnd: //Test rand() and rands() -char countr, rndnum, rndtbl[255]; - -rands(1); //Seed Random Number Generator; - -countr = 0; - -riloop: - rndtbl[countr] = 0; - countr++; - if (countr <> 0) goto riloop; - -rnloop: - rndnum = rand(); - if (rndtbl[rndnum] > 0) goto rnderr; - rndtbl[rndnum] = $FF; - prbyte(rndnum); - prchr(' '); - countr++; - if (countr < 255) goto rnloop; - newlin(); - prchr('R'); - prchr('A'); - prchr('N'); - prchr('D'); - prchr(' '); - prchr('O'); - prchr('K'); - newlin(); - -tstc2a: //Test ctoa(); -char srcchr, dstchr, tststr[4]; - -srcchr = 0; -caloop: - prbyte(srcchr); - prchr(' '); - ctoa(srcchr, &tststr); - dstchr = atoc(&tststr); - if (srcchr <> dstchr) goto c2aerr; - srcchr++; - if (srcchr <> 0) goto caloop; - newlin(); - prchr('C'); - prchr('T'); - prchr('O'); - prchr('A'); - prchr(' '); - prchr('O'); - prchr('K'); - newlin(); - - -goto exit; - -abserr: - prchr('A'); - prchr('B'); - prchr('S'); - prchr('('); - prbyte(onum); - prchr(')'); - prchr('='); - prbyte(anum); - prchr(','); - prbyte(cnum); - newlin(); - goto exit; - -merror: - newlin(); - prbyte(mltplr); - prchr('*'); - prbyte(mltpnd); - prchr('='); - //prbyte(ovrflw); - prbyte(prodct); - prchr(','); - //prbyte(acmmsb); - prbyte(acmlsb); - newlin(); -goto exit; - -derror: - newlin(); - prbyte(divdnd); - prchr('/'); - prbyte(divisr); - prchr('='); - prbyte(quotnt); - prchr(','); - prbyte(mltplr); - newlin(); -goto exit; - -rnderr: - prchr('R'); - prchr('A'); - prchr('N'); - prchr('D'); - prchr('('); - prchr(')'); - prchr('='); - prbyte(rndnum); - prchr(','); - prbyte(countr); - newlin(); - goto exit; - -c2aerr: - prchr('C'); - prchr('T'); - prchr('O'); - prchr('A'); - prchr('('); - prbyte(srcchr); - prchr(')'); - prchr('='); - prbyte(dstchr); - newlin(); - goto exit; - diff --git a/test/v8k.bat b/test/v8k.bat index 1680e0a..14530ae 100644 --- a/test/v8k.bat +++ b/test/v8k.bat @@ -8,8 +8,8 @@ ECHO Compiling File %1.c02 for VIC 20 +8k ..\c02.exe -h vic8k -s vic -s cbm %1 >%1.dbg IF %ERRORLEVEL% NEQ 0 GOTO EOF ECHO Assembling File %1.asm -C:\Programs\dasm %1.asm -f1 -o%1.prg -l%1.lst -s%1.sym - +..\a02.exe -p %1.asm %1.prg %1.lst >%1.out +REM C:\Programs\dasm %1.asm -f1 -o%1.prg -l%1.lst -s%1.sym IF %ERRORLEVEL% NEQ 0 GOTO EOF ECHO Starting Emulator diff --git a/test/xmemtest.c02 b/test/xmemtest.c02 new file mode 100644 index 0000000..47ead14 --- /dev/null +++ b/test/xmemtest.c02 @@ -0,0 +1,272 @@ +/************************************** + * TESTXMEM - Test Library xmemory.h02 * + **************************************/ + +//use -h option on command line +#include +#include +#include +#include +#include +#include +#include + +char aa; //Function Arguments + +alias char banked = $A000; //Beginning of Banked Memory +int icount; + +char i; //Index Variable +char chrctr; //Get/Put Character +int intger; //Get/Put Integer +char r[255],w[255]; //Read/Write Arrays + +char ibank, ipage, ibyte; //Index Bank, Page, and Byte +char lbank, lpage, lbyte; //Logical Bank, Page, and Byte +char mbank, mpage, mbyte; //Memory Bank, Page, and Byte +char pbank, ppage, pbyte; //Physical Bank, Page, and Byte +char sbank, spage, sbyte; //Starting Bank, Page, and Byte +char ebank, epage, ebyte; //Starting Bank, Page, and Byte + +void passed() { putln("PASSED");} + +void paddrs(aa) { + if (aa) newlin(); else puts(", "); + printf(setdst(xgetpa()),"PA=$%h%w, "); + printf(setdst(xgetla()),"LA=$%h%w "); +} + +void perror() { + printf(); //Implied Arguments + paddrs(#FALSE); + newlin(); + goto exit; +} + +/* Test xclcpa() and xclcla() */ +void tstlpl(sbank,spage,sbank) { + ibank=sbank; ipage=spage; ibyte=sbyte; + while (ibank<=#XLBANK) { + putc('.'); + while() { + while() { + //printf(setdst(ibank,ipage,ibyte),"%n ORIGINAL: $%h%w"); + pbank,ppage,pbyte = xclcpa(ibank,ipage,ibyte); + //printf(setdst()," PHYSICAL: $%h%w"); + lbank,lpage,lbyte = xclcla(pbank,ppage,pbyte); + //printf(setdst(),", LOGICAL: $%h%w"); + if (lbank<>ibank or lpage<>ipage or ibyte<>lbyte) + perror(setdst(ibank,ipage,ibyte),"%nERROR IN BANK $%h ADDRESS $%w"); + if (getkey()==#ESCKEY) goto exit; + ibyte=ibyte+$10; if (!ibyte) break; + } ipage++; if (!ipage) break; + } ibank++; if (!ibank) break; + } +} + +/* Test xgetla() and xsetla() */ +void tstgsl(ibank,ipage,ibank) { + while (ibank<=#XLBANK) { + putc('.'); + while() { + while() { + //printf(setdst(ibank,ipage,ibyte),"%n SET: $%h%w"); + xsetla(ibank,ipage,ibyte); + lbank,lpage,lbyte = xgetla(); + //printf(setdst(),", GOT: $%h%w"); + if (lbank<>ibank or lpage<>ipage or ibyte<>lbyte) + perror(setdst(ibank,ipage,ibyte),"%nERROR IN BANK $%h ADDRESS $%w"); + if (getkey()==#ESCKEY) goto exit; + ibyte=ibyte+$10; if (!ibyte) break; + } ipage++; if (!ipage) break; + } ibank++; if (!ibank) break; + } +} + +/* Test xincpa() */ +void tstipa(ibank,ipage,ibank) { + xsetla(ibank,ipage,ibyte); //Set Logical Address to 0 + while (ibank<=#XLBANK) { + putc('.'); + while() { + //clrscr(); + while() { + pbank,ppage,pbyte = xgetpa(ibank,ipage,ibyte); + //printf(setdst(),"$%h%w:"); + lbank,lpage,lbyte = xgetla(); //Get Logical Address + //printf(setdst(),"$%h%w "); + if (lbank<>ibank or lpage<>ipage or ibyte<>lbyte) + perror(setdst(ibank,ipage,ibyte),"%nERROR IN BANK $%h ADDRESS $%w"); + xincpa(); //Increment Physical Address + ibyte++; if (!ibyte) break; + } ipage++; if (!ipage) break; + if (getkey()==#ESCKEY) goto exit; + } ibank++; if (!ibank) break; + } +} + +/* Test xgetc() and xputc() */ +void tstgpc(sbank,spage,sbyte) { + while() { + //printf(setdst(),"$%h%w"); + putc('.'); + ibank=sbank; ipage=spage; ibyte=sbyte; + xsetla(ibank,ipage,ibyte); + i=0; do { xputc(i); i++; } while (i); + xsetla(ibank,ipage,ibyte); + i=0; do { + if (xgetc()<>i) perror(setdst(xgetpa()),"%nERROR IN BANK $%h ADDRESS $%w"); + i++; + } while (i); + sbank++;spage++;sbyte++; + if (!sbank or sbank>#XLBANK) break; + } +} + +/* Test xgeti() and xputi() */ +void tstgpi(sbank,spage,sbyte) { + while() { + //*printf(setdst(),"$%h%w"); + putc('.'); + ibank=sbank; ipage=spage; ibyte=sbyte; + //Write 256 Integers + xsetla(ibank,ipage,ibyte); + i=0; do { + mpage=i;mbyte=i^$FF; + xputi(.,mpage,mbyte); + i++; + } while (i); + //Read 256 Integers + xsetla(ibank,ipage,ibyte); + i=0; do { + mpage=i;mbyte=i^$FF; + intger = xgeti(); + if (mbyte or >intger<>mpage) + perror(setdst(xgetpa()),"%nERROR IN BANK $%h ADDRESS $%w"); + i++; + } while (i); + //Set Next Start Address + sbank++;spage++;sbyte++; + if (!sbank or sbank>#XLBANK) break; + } +} + +/* Test xgetl() and xputl() */ +void tstgpl(sbank,spage,sbyte) { + while() { + //*printf(setdst(),"$%h%w"); + putc('.'); + ibank=sbank; ipage=spage; ibyte=sbyte; + //Write 256 Integers + xsetla(ibank,ipage,ibyte); + i=0; do { + mbyte=i; mpage=i^$FF; mbank = -i; + xputi(mbank,mpage,mbyte); + i++; + } while (i); + //Read 256 Integers + xsetla(ibank,ipage,ibyte); + i=0; do { + mbyte=i; mpage=i^$FF; mbank = -i; + intger = xgeti(); + if (mbyte or >intger<>mpage) + perror(setdst(xgetpa()),"%nERROR IN BANK $%h ADDRESS $%w"); + i++; + } while (i); + //Set Next Start Address + sbank++;spage++;sbyte++; + if (!sbank or sbank>#XLBANK) break; + } +} + +/* Test xread() and xwrite() */ +void tstxrw(sbank,spage,epage) { + i=0; do {w[i]=i;i++;} while (i); //Fill Write Array + ibank=sbank; + while (ibank<=#XLBANK) { + putc('.'); + //Write 256,1-255 bytes of Array + ipage=spage; xsetla(ibank,0,ipage); + do { + //paddrs(#TRUE); + //inline $ff; + xwrite(ipage,&w); + //if (banked=61) perror("MEMORY OVERWRITE ERROR!"); + ipage++; + } while (ipage<>epage); + //paddrs(#TRUE); + //Read 256,1-255 bytes of Array + ipage=spage; xsetla(ibank,0,ipage); + do { + //printf(ipage,"%n%h:"); + //inline $ff; + //paddrs(#TRUE); + xread(ipage,&r); + i=0; do { + //printf(r[i],"%h."); printf(w[i],"%h,"); + if (r[i]<>w[i]) perror(i,"ERROR IN INDEX %d"); + i++; + } while(i<>ipage); + ipage++; + } while (ipage<>epage); + ibank++; if (!ibank) break; + } +} + +/* Test xload() and xsave() */ +void tstxls(sbank,spage,sbyte) { + setsrc(&$F000); //Most Systems have ROM from $F000 to $FFFF + xsetla(sbank,spage,sbyte); + xsave(&$1000); //Save through $FFFF + setdst(&$8000); //There's usually free RAM here + xsetla(sbank,spage,sbyte); + xload(&$1000); //Load bytes saved from $F000 to $FFFF + srcptr = &$F000; dstptr = &$8000; icount = &$1000; + while (icount) { + //putwrd(srcptr); putchr(':'); puthex(*srcptr); putspc(); + //putwrd(dstptr); putchr(':'); puthex(*dstptr); putspc(); + if (*srcptr <> *dstptr) perror("ERROR IN XLOAD() AND/OR XSAVE()\n"); + if (!%1.out diff --git a/work/a02inc.a02 b/work/a02inc.a02 new file mode 100644 index 0000000..415a6ea --- /dev/null +++ b/work/a02inc.a02 @@ -0,0 +1,18 @@ +;A02 Assembler Test Include File + +TRUE: EQU $FF +FALSE: .EQU $00 + +one equ 1 +two .equ 1 + 1 +three equ one + one + one +four .equ three + 1 + + +PNTR: EQU $80 +.local EQU 99 +STRUCT EQU $0FFF + + .END ;Return to Main File + +IGNORE EQU $9999 ;This will Not be Assembled \ No newline at end of file diff --git a/work/a02test.a02 b/work/a02test.a02 new file mode 100644 index 0000000..83b2dcb --- /dev/null +++ b/work/a02test.a02 @@ -0,0 +1,103 @@ +;A02 Assembler Test File + + INCLUDE "a02inc.a02" + +start ORG $0400 ;Start of Code + SUBROUTINE +flags: CLC + SEC + CLI + SEI + CLV + CLD +.local SED + SUBROUTINE +rgstr: DEX + DEY + INX + INY + TAX + TAY + TSX + TXA + TXS + TYA + SUBROUTINE +retrn: RTI + RTS + SUBROUTINE +stack: PHA + PHP + PHX + PHY + PLA + PLP + PLX + PLY + SUBROUTINE +other: NOP + BRK + SUBROUTINE +branch: BCC rgstr + BCS flags +.loop BEQ retrn + BNE jump + BMI .next + BPL .loop + BRA branch +.next BVC +127 + BVS -128 + SUBROUTINE +jump JMP .next + JMP (words ) + JMP (pntr,x) +.next JSR retrn + SUBROUTINE +memory: ADC #$98 ;Immediate + AND TABLE,Y ;Absolute,Y + CMP PNTR,Y ;Absolute,Y (Zero Page Address) + EOR (PNTR,X) ;(Indirect,X) + LDA (PNTR),Y ;(Indirect),Y + ORA (PNTR) ;(Indirect) + ASL ;Accumulator + DEC PNTR ;ZeroPage + INC PNTR,X ;ZeroPage,X + LSR BYTES ;Absolute + ROL BYTES,X ;Absolute,X + ROR $ABCD,X ;Absolute,X + CPX #$76 ;Immediate + CPY PNTR ;ZeroPage + STY PNTR,X ;ZeroPage,X + STZ $CDEF ;Absolute + LDY $CDEF,X ;Absolute,X + TRB PNTR ;ZeroPage + TSB $1234 ;Absolute + SUBROUTINE +exprsn LDA #PNTR+1 ;Immediate + LDA PNTR+1 ;ZeroPage + LDA (PNTR+2) ;Indirect + LDA (PNTR+4,X) ;(Indirect,X) + LDA (PNTR+6),Y ;(Indirect),Y + LDA STRUCT ;Absolute + LDX #STRUCT ;MSB Immediate + LDA STRUCT+1 + LDX #STRUCT+1 + LDA STRUCT+2 + LDX #<(STRUCT+2) + LDY #>(STRUCT+2) + +BYTES byte 99, %10101010,'~' ;Bytes + .byte $12,$34 +HEXES hex 01,23,45,67,89 ;Hexadecimal + .hex ,AB,CD,EF,1A,2B,3C,D4,E5,F6 +WORDS word $3456 + Align 256 +TABLE .word $1357,$9BDF,$2468 +TEXT byte "ABCDEFGHIJKLMNOPQRSTUVWXYZ",0 + + END ;Nothing after this will be Assembled + STY (STRUCT),X ;Illegal Addressing Mode + DC.W ;Unsupported Pseudo-Op + diff --git a/work/c02.bat b/work/c02.bat index 3b7f2af..0a3528d 100644 --- a/work/c02.bat +++ b/work/c02.bat @@ -1,3 +1,3 @@ @ECHO Compiling File %1.c02 -..\c02.exe %1 >%1.dbg +..\c02.exe -c 65C02 %1 >%1.dbg diff --git a/work/notes.txt b/work/notes.txt deleted file mode 100644 index 6b50581..0000000 --- a/work/notes.txt +++ /dev/null @@ -1,8 +0,0 @@ -OP VALUE -= 1 -< 2 -<= 3 -> 4 ->= 5 -<> 6 - diff --git a/work/opcodes.a02 b/work/opcodes.a02 new file mode 100644 index 0000000..05ccfeb --- /dev/null +++ b/work/opcodes.a02 @@ -0,0 +1,258 @@ + PROCESSOR 6502 + ORG $1000 +X00 BRK ;00 +X01 ORA ($10,X) ;01 +X02 BYTE $02 ;NOP #IMD +X03 BYTE $03 ;NOP +X04 TSB $40 ;04 +X05 ORA $50 ;05 +X06 ASL $60 ;06 +X07 RMB 0,$70 ;07 +X08 PHP ;08 +X09 ORA #$90 ;09 +X0A ASL ;0A +X0B BYTE $0B ;NOP +X0C TSB $CBA9 ;0C +X0D ORA $DCBA ;0D +X0E ASL $EDCB ;0E +X0F BBR0 $F0,X00 ;0F +X10 BPL X11 ;10 +X11 ORA ($11),Y ;11 +X12 BYTE $12 ;NOP #IMD +X13 BYTE $13 ;NOP +X14 TRB $51 ;14 +X15 ORA $61,X ;15 +X16 ASL $71,X ;16 +X17 RMB1 $71 ;17 +X18 CLC ;18 +X19 ORA $A987,Y ;19 +X1A BYTE $1A ;1A +X1B BYTE $1B ;1A +X1C TRB $CBA9 ;1C +X1D ORA $DCBA,X ;1D +X1E ASL $EDCB,X ;1E +X1F BBR 1,$F1,X11 ;1F +X20 JSR $0123 ;20 +X21 AND ($12,X) ;21 +X22 BYTE $22 ;NOP #IMD +X23 BYTE $23 ;NOP +X24 BIT $42 ;24 +X25 AND $52 ;25 +X26 ROL $62 ;26 +X27 RMB 2,$72 ;27 +X28 PLP ;28 +X29 AND #$92 ;29 +X2A ROL ;2A +X2B BYTE $2B ;2B +X2C BIT $CBDA ;2C +X2D AND $DCBA ;2D +X2E ROL $EDCB ;2E +X2F BBR2 $F2,X22 ;2F +X30 BMI X33 ;30 +X31 AND ($13),Y ;31 +X32 BYTE $32 ;NOP #IMD +X33 BYTE $33 ;NOP +X34 BIT $43,X ;34 +X35 AND $53,X ;35 +X36 ROL $63,X ;36 +X37 RMB3 $73 ;37 +X38 SEC ;38 +X39 AND $9876,Y ;39 +X3A DEC ;3A +X3B BYTE $3B ;NOP +X3C BIT $CBA9,X ;3C +X3D AND $DCBA,X ;3D +X3E ROL $EDCB,X ;3E +X3F BBR 3,$F3,X33 ;3F +X40 RTI ;40 +X41 EOR ($14,X) ;41 +X42 BYTE $42 ;NOP #IMD +X43 BYTE $43 ;NOP +X44 BYTE $44 ;NOP $ZP +X45 EOR $54 ;45 +X46 LSR $64 ;46 +X47 RMB 4,$74 ;47 +X48 PHA ;48 +X49 EOR #$94 ;49 +X4A LSR ;4A +X4B BYTE $4B ;NOP +X4C JMP $CBA9 ;4C +X4D EOR $DCBA ;4D +X4E LSR $EDCB ;4E +X4F BBR4 $F4,X44 ;4F +X50 BVC X55 ;50 +X51 EOR ($15),Y ;51 +X52 EOR ($25) ;52 +X53 BYTE $53 ;NOP +X54 BYTE $54 ;NOP $ZP +X55 EOR $55,X ;55 +X56 LSR $65,X ;56 +X57 RMB5 $75 ;57 +X58 CLI ;58 +X59 EOR $9876,Y ;59 +X5A PHY ;5A +X5B BYTE $5B ;NOP +X5C BYTE $5C ;NOP $ABSL +X5D EOR $CBA9,X ;5C +X5E LSR $DCBA,X ;5E +X5F BBR 5,$F5,X55 ;5F +X60 RTS ;60 +X61 ADC ($16,X) ;61 +X62 BYTE $62 ;NOP #IMD +X63 BYTE $63 ;NOP +X64 STZ $46 ;64 +X65 ADC $56 ;65 +X66 ROR $66 ;66 +X67 RMB 6,$76 ;67 +X68 PLA ;68 +X69 ADC #$96 ;69 +X6A ROR ;6A +X6B BYTE $6B ;NOP +X6C JMP ($CDBA) ;6C +X6D ADC $DCBA ;6D +X6E ROR $EDCB ;6E +X6F BBR6 $F6,X66 ;6F +X70 BVS X77 ;70 +X71 ADC ($17),Y ;71 +X72 ADC ($27) ;72 +X73 BYTE $73 ;NOP +X74 STZ $47,X ;74 +X75 ADC $57,X ;75 +X76 ROR $67,X ;76 +X77 RMB7 $77 ;77 +X78 SEI ;78 +X79 ADC $9875,Y ;79 +X7A PLY ;7A +X7B BYTE $7B ;NOP +X7C JMP ($C7,X) ;7C +X7D ADC $DCBA,X ;7E +X7E ROR $DCBA,X ;7E +X7F BBR 7,$F1,X77 ;7F +X80 BRA X88 ;80 +X81 STA ($18,X) ;81 +X82 BYTE $82 ;NOP #IMD +X83 BYTE $83 ;NOP +X84 STY $48 ;84 +X85 STA $58 ;85 +X86 STX $68 ;86 +X87 SMB0 $78 ;87 +X88 DEY ;88 +X89 BIT #$98 ;89 +X8A TXA ;8A +X8B BYTE $8B ;NOP +X8C STY $CBA9 ;8C +X8D STA $DCBA ;8D +X8E STX $EDCB ;8E +X8F BBS 0,$F8,X88 ;8F +X90 BCC X99 ;90 +X91 STA ($19),Y ;91 +X92 STA ($29) ;92 +X93 BYTE $93 ;NOP +X94 STY $49,X ;94 +X95 STA $59,X ;95 +X96 STX $69,Y ;96 +X97 SMB1 $79 ;97 +X98 TYA ;98 +X99 STA $9876,Y ;99 +X9A TXS ;9A +X9B BYTE $9B ;NOP +X9C STZ $CBA9 ;9C +X9D STA $DCBA,X ;90 +X9E STZ $EDCB,X ;9E +X9F BBS1 $F9,X99 ;8F +XA0 LDY #$0A ;A0 +XA1 LDA ($1A,X) ;A1 +XA2 LDX #$2A ;A2 +XA3 BYTE $A3 ;NOP +XA4 LDY $4A ;A4 +XA5 LDA $5A ;A5 +XA6 LDX $6A ;A6 +XA7 SMB1 $7A ;A7 +XA8 TAY ;A8 +XA9 LDA #$9A ;A9 +XAA TAX ;AA +XAB BYTE $AB ;NOP +XAC LDY $CBA9 ;AC +XAD LDA $DCBA ;AD +XAE LDX $EDCB ;AE +XAF BBS 2,$FA,XAA ;AF +XB0 BCS XBB ;B0 +XB1 LDA ($1B),Y ;B1 +XB2 LDA ($2B) ;B2 +XB3 BYTE $B3 ;NOP +XB4 LDY $B4,X ;B4 +XB5 LDA $B5,X ;BS +XB6 LDX $B6,Y ;B6 +XB7 SMB3 $7B ;B7 +XB8 CLV ;B8 +XB9 LDA $9876,Y ;B9 +XBA TSX ;BA +XBB BYTE $BB ;NOP +XBC STX $CBA9,Y ;BC +XBD LDA $DCBA,X ;BD +XBE LDX $EDCB,Y ;BE +XBF BBS3 $FB,XBB ;BF +XC0 CPY #$0C ;C0 +XC1 CMP ($1C,X) ;C1 +XC2 BYTE $C2 ;NOP #imd +XC3 BYTE $C3 ;NOP +XC4 CPY $4C ;C4 +XC5 CMP $5C ;C5 +XC6 DEC $6C ;C6 +XC7 SMB4 $7C ;C7 +XC8 INY ;C8 +XC9 CMP #$9C ;C9 +XCA DEX ;CA +XCB WAI ;CB +XCC CPY $CBA9 ;CC +XCD CMP $DCBA ;CD +XCE DEC $EDCB ;CE +XCF BBS 4,$FC,XCC ;8F +XD0 BNE XDD ;D0 +XD1 CMP ($1D),Y ;D1 +XD2 CMP ($2D) ;D2 +XD3 BYTE $D3 ;NOP +XD4 BYTE $D4 ;NOP $ZP,X +XD5 CMP $5D,X ;D5 +XD6 DEC $6D,X ;D6 +XD7 SMB5 $7D ;D7 +XD8 CLD ;D8 +XD9 CMP $9876,Y ;D9 +XDA PHX ;DA +XDB STP ;DB +XDC BYTE $DC ;NOP $ABSL +XDD CMP $DCBA,X ;DD +XDE DEC $EDCB,X ;DE +XDF BBS5 $FD,XDD ;8F +XE0 CPX #$0E ;E0 +XE1 SBC ($1E,X) ;E1 +XE2 BYTE $E2 ;NOP #IMD +XE3 BYTE $E3 ;NOP +XE4 CPX $4E ;E4 +XE5 SBC $5E ;E5 +XE6 INC $6E ;E6 +XE7 SMB6 $7E ;E7 +XE8 INX ;E8 +XE9 SBC #$9E ;E9 +XEA NOP ;EA +XEB BYTE $EB ;NOP +XEC CPX $CBA9 ;EC +XED SBC $DCBA ;ED +XEE INC $EDCB ;EE +XEF BBS 6,$FE,XEE ;8F +XF0 BEQ XFF ;F0 +XF1 SBC ($1F),Y ;F1 +XF2 SBC ($2F) ;F2 +XF3 BYTE $F3 ;NOP +XF4 BYTE $F4 ;NOP $ZP,X +XF5 SBC $5F,X ;F5 +XF6 INC $6F,X ;F6 +XF7 SMB7 $7F ;F7 +XF8 SED ;F8 +XF9 SBC $9876,Y ;F9 +XFA PLX ;FA +XFB BYTE $FB ;NOP +XFC BYTE $FC ;NOP $ABSL +XFD SBC $DCBA,X ;FD +XFE INC $EDCB,X ;FE +XFF BBS7 $FF,XFF ;8F