Modified intlib to use system vars intacc, intarg, and intovr

This commit is contained in:
Curtis F Kaylor 2022-04-04 19:47:16 -04:00
parent 8495b43011
commit a220bd0592
7 changed files with 729 additions and 327 deletions

224
a02.c
View File

@ -1,7 +1,6 @@
/* Simple 6502 Assembler * /* 6502 Assembler for C02 Compiler *
* for C02 Compiler * * Uses DASM Syntax but supports *
* Uses DASM Syntax but * * 65C02 and Sweet 16 Opcodes */
* supports 65C02 Op Codes */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -15,13 +14,23 @@ int debug; //Ouput Debug Info
#define INCLEN 255 #define INCLEN 255
char incpath[INCLEN]; char incpath[INCLEN];
enum otypes {BINFIL, PRGFIL}; //Object File Types enum otypes {BINFIL, APLFIL, ATRFIL, INTFIL, MSRFIL, PRGFIL}; //Object File Types
int obin[] = {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE}; //Is File Type Binary
int olen[] = {0, 8, 32, 0, 0}; //Hex Bytes per Line
char objtyp; //Object File Type char objtyp; //Object File Type
int objbin; //Binary Object File Flag
int objlen; //Text Object File Line Length
int objcnt; //Text Object File Byte Count
int chksum; //Text Object File Checksum
int orgadr; //Origin Address int orgadr; //Origin Address
int curadr; //Current Address int curadr; //Current Address
int endadr; //Address after Last Byte
int exeadr; //Execution Start Address
int lstadr; //List Address int lstadr; //List Address
char hdrtxt[MAXSTR]; //SREC Header Record Text
struct sym {int block; char name[MAXLBL+1]; int bytes, value, refrd;}; struct sym {int block; char name[MAXLBL+1]; int bytes, value, refrd;};
struct sym symbol; //Current Symbol struct sym symbol; //Current Symbol
struct sym symtbl[MAXSYM]; //Global Symbol Table struct sym symtbl[MAXSYM]; //Global Symbol Table
@ -36,6 +45,7 @@ char cmmnt[MAXSTR]; //Assembly Line Comment
char mcode[MAXSTR]; //Generated Bytes char mcode[MAXSTR]; //Generated Bytes
char strng[MAXSTR]; //Parsed String char strng[MAXSTR]; //Parsed String
int opridx; //Index into Operand int opridx; //Index into Operand
char cpdchr; //Last Character Copied into oprnd char cpdchr; //Last Character Copied into oprnd
@ -67,8 +77,13 @@ FILE *incfil; //Include File Pointer
/* Print Usage Info and Exit */ /* Print Usage Info and Exit */
void usage(char* appnam) { void usage(char* appnam) {
printf("Usage: %s [opts] asmfile objfile [lstfile]\n", appnam); printf("Usage: %s [opts] asmfile objfile [lstfile]\n", appnam);
printf(" Opts: -p - Commodore PRG format\n"); printf(" Opts: -d - Output debug info\n");
printf(" -d - Output Debug Info\n"); printf(" -h - SREC header record text\n");
printf(" -a - Apple-1 monitor format\n");
printf(" -p - Commodore PRG format\n");
printf(" -s - Motorola SREC format\n");
printf(" -x - Intel HEX format");
printf(" \n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@ -105,15 +120,18 @@ void xerror(char* format, char *s) {
/* Open File with Error Checking */ /* Open File with Error Checking */
FILE * opnfil(char* name, char* mode, char* path) { FILE * opnfil(char* name, char* mode, char* path) {
if (debug) printf("Opening file '%s' with mode '%s'\n", name, mode); if (debug) printf("Opening file '%s' with mode '%s'\n", name, mode);
if (debug && strlen(path)) printf("using path list '%s'\n", path);
FILE *fp = fopen(name, mode); FILE *fp = fopen(name, mode);
if (!fp) { if (!fp) {
char spec[256]; char spec[256], paths[256];
char *token = strtok(path, " "); strcpy(paths, path);
while (token) { char *token = strtok(paths, " ");
strcpy(spec, path); strcat(spec, "\\"); strcat(spec, name); while (token != NULL) {
strcpy(spec, token); strcat(spec, "\\"); strcat(spec, name);
if (debug) printf("Opening file \"%s\" with mode \"%s\"\n", spec, mode); if (debug) printf("Opening file \"%s\" with mode \"%s\"\n", spec, mode);
fp = fopen(spec, mode); if (fp) break; fp = fopen(spec, mode); if (fp) break;
token = strtok(NULL, " "); token = strtok(NULL, " ");
if (debug) printf("token = \"%s\"\n", token);
} }
} }
if (!fp) xerror("Error Opening File '%s'\n", name); if (!fp) xerror("Error Opening File '%s'\n", name);
@ -121,6 +139,17 @@ FILE * opnfil(char* name, char* mode, char* path) {
return fp; return fp;
} }
/* Open Object FIle */
FILE * opnobj(char* objnam, char* path) {
char mode[3] = "w";
objbin = obin[objtyp];
if (debug) printf("Set objbin to %d\n", objbin);
objlen = olen[objtyp];
if (debug) printf("Set objlen to %d\n", objlen);
if (objbin) strcat(mode, "b");
return opnfil(objnam, mode, path);
}
/* Skip Character in Input Line * /* Skip Character in Input Line *
* Args: c - Character to Skip * * Args: c - Character to Skip *
* Updates: linptr */ * Updates: linptr */
@ -205,11 +234,16 @@ int plabel(void) {
return found; return found;
} }
/* Append to Operand */
void aoprnd(int c) {
if (opridx < MAXSTR) oprnd[opridx++] = toupper(c);
}
/* Copy Character to Operand and Increment */ /* Copy Character to Operand and Increment */
int cpychr(int c) { int cpychr(int c) {
if (c && toupper(*linptr) != c) return FALSE; if (c && toupper(*linptr) != c) return FALSE;
cpdchr = *linptr; cpdchr = *linptr;
if (opridx < MAXSTR) oprnd[opridx++] = toupper(cpdchr); aoprnd(cpdchr);
linptr++; linptr++;
return TRUE; return TRUE;
} }
@ -324,11 +358,66 @@ int evlopd(int maxsiz) {
return result; return result;
} }
/* Write Hex and Update Checksum */
void outhex(char prefix, int b) {
if (prefix) fputc(prefix, outfil);
fprintf(outfil, "%02X", b);
chksum += b;
} \
/* Write Hex Address */
void outadr(int w) {
outhex(0, w >> 8);
outhex(0, w & 0xFF);
}
/* Write Hex File Line Header */
void outhdr(int addr) {
chksum = 0;
int linlen = __min(objlen, endadr - curadr + 1);
if (debug) printf("outhdr: curadr=%04x, endadr=%04x, linlen=%04x\n", curadr, endadr, linlen);
switch (objtyp) {
case INTFIL: outhex(':', linlen); outadr(addr); outhex(0, 0); break;
default: outadr(addr); //Write Address
}
if (objtyp == APLFIL) fputc(':', outfil);
}
/* Write Checksum */
void outchk(void) {
if (objtyp == INTFIL) outhex(0, -chksum & 0xFF);
}
/* Write Hex File Line End */
void outend(void) {
if (objtyp = INTFIL) outchk(); //Write Checksum
fputs("\n", outfil);
objcnt = 0;
}
/* Write Hex File End of File */
void outeot(void) {
if (objcnt) outend();
if (objtyp = INTFIL); fputs(":00000001FF\n", outfil);
}
/* Write Byte to Hex Object File */
void outtxt(int b) {
if (objcnt == 0) outhdr(curadr - 1);
switch (objtyp) {
case APLFIL: outhex(' ', b); break;
default: outhex(0, b);
}
objcnt++;
if (objcnt == objlen) outend();
}
/* Write Byte to Output File */ /* Write Byte to Output File */
void outbyt(int b) { void outbyt(int b) {
if (curadr > -1) curadr++; if (curadr > -1) curadr++;
if (passno != 2) return; if (passno != 2) return;
fputc(b & 0xFF, outfil); if (objbin) fputc(b & 0xFF, outfil);
else outtxt(b);
sprintf(bytstr, "%02X ", b); sprintf(bytstr, "%02X ", b);
if (strlen(mcode) < 9) strcat(mcode, bytstr); if (strlen(mcode) < 9) strcat(mcode, bytstr);
} }
@ -339,6 +428,20 @@ void outwrd(int w) {
outbyt(w >> 8); outbyt(w >> 8);
} }
/* Write Atari 8-Bit EXE Block Header */
void atrhdr(int saddr, int eaddr) {
outwrd(0xFFFF); //Binary File Indicator
outwrd(saddr); //Start Address
outwrd(eaddr-1); //End Address
}
/* Write Atari 8-Bit EXE Ending Block */
void atrend(void) {
atrhdr(0x02E0, 0x02E2);
outbyt(0x4C); //JMP
outwrd(exeadr); //start address
}
/* Lookup Opcode */ /* Lookup Opcode */
int lkpopc(struct opc opl[]) { int lkpopc(struct opc opl[]) {
if (debug) printf("Looking up Mnemonic %s\n", mnmnc); if (debug) printf("Looking up Mnemonic %s\n", mnmnc);
@ -403,15 +506,23 @@ void asmequ(void) {
setsym(evlopd(0xFFFF), 0); setsym(evlopd(0xFFFF), 0);
} }
/* Assemble EXE Pseudo-Op */
void asmexe(void) {
exeadr = evlopd(0xFFFF);
}
/* Assemble ORG Pseudo-Op */ /* Assemble ORG Pseudo-Op */
void asmorg(void) { void asmorg(void) {
orgadr = evlopd(0xFFFF); orgadr = evlopd(0xFFFF);
if (exeadr < 0) exeadr = orgadr;
if (passno == 1 && symbol.name[0]) { if (passno == 1 && symbol.name[0]) {
symbol.value = orgadr; symbol.value = orgadr;
symbol.bytes = 2; symbol.bytes = 2;
} }
if (passno == 2 && objtyp == PRGFIL) if (passno == 2 ) {
outwrd(orgadr); if (objtyp == PRGFIL) outwrd(orgadr);
if (objtyp == ATRFIL) atrhdr(orgadr, lstadr);
}
curadr = orgadr; curadr = orgadr;
lstadr = orgadr; lstadr = orgadr;
} }
@ -473,6 +584,7 @@ int asmpso(int dot) {
case 'M': asmens(); break; //ENDSubroutine case 'M': asmens(); break; //ENDSubroutine
case 'I': asminf(); break; //INCLude case 'I': asminf(); break; //INCLude
case '*': asmorg(); break; //ORG case '*': asmorg(); break; //ORG
case 'X': asmexe(); break; //EXEC
case 'P': asmprc(); break; //PROCessor case 'P': asmprc(); break; //PROCessor
case 'E': asmend(); break; //END case 'E': asmend(); break; //END
case 'A': asmaln(); break; //ALIGn case 'A': asmaln(); break; //ALIGn
@ -607,17 +719,76 @@ void dbgopc(void) {
} }
} }
/* Evaluate Register Operand *
* Returns: Register Number 0-15 */
int evlreg(void) {
char name[MAXSTR];
int result;
if (debug) puts("Evaluating Register Argument");
int rel = cpychr('@');
if (debug) printf("Set rel to %d\n", rel);
if (amode == INDCT && !rel) xerror("Indirect Argument Required\n", "");
if (amode == RGIND && rel) token = token + 0x20; //LD or ST relative
char pfx = 'R'; if (!cpychr(pfx)) pfx = 0;
if (debug) puts("Evaulating Register Number");
if (pfx && isalpha(*linptr)) return evlhex(0x0F);
if (isdigit(*linptr)) return evldec(0x0F);
if (!pword(FALSE, name)) xerror("Register Argument Required\n", "");
for (int i=0; name[i]; i++) if (opridx<MAXSTR) oprnd[opridx++] = name[i];
if (pfx) pfxstr(pfx, name);
if (debug) printf("Parsed Register Name %s \n", name);
if (strcmp(name, "ACC")==0) return 0; //Accumulator (R0)
if (strcmp(name, "PR")==0) return 14; //Prior Result (R14)
if (strcmp(name, "PC")==0) return 15; //Accumulator (R0)
xerror("Illegal Register %s\n", name);
}
/* Assemnble Register Instruction */
void asmreg(void){
if (debug) printf("Assembling Register Opcode %02x\n", token);
int regno = evlreg();
if (debug) printf("Register Number: %d\n", regno);
token = token | regno;
if (amode == ABSLT) {
if (debug) puts("Evaluating Absolure Argument");
skpspc();
if (!cpychr(',')) aoprnd(' '); //Skip optional comma
opval = evlopd(0xFFFF);
if (opval < 0) xerror("Absolute Argument Required\n", "");
}
}
/* Assemble Sweet 16 Opcode */
int asmswo(void) {
opval = -1;
if (lkpopc(swolst) == FALSE) return FALSE;
if (debug) printf("Assembling Sweet 16 Instruction %s, ", mnmnc);
if (debug) printf("Addressing Mode 0x%04X\n", amode);
skpspc();
switch (amode) {
case IMPLD: break; //Implied Instruction
case RELTV: asmbrn(TRUE); break; //Branch (Relative) Instruction
default: asmreg(); //Assemble Register Instruction
}
if (debug) printf("Writing OpCode $%02X\n", token);
outbyt(token);
if (debug) printf("Writing %s Operand %d\n", zpgabs[-zpage], opval);
if (opval >= 0) {if (amode == RELTV) outbyt(opval); else outwrd(opval);}
return TRUE;
}
/* Assemble Opcode */ /* Assemble Opcode */
int asmopc(int dot) { int asmopc(int dot) {
opmod = 0; opmod = 0;
if (asmpso(dot)) return TRUE; //Check For/Assemble Pseudo-Op if (asmpso(dot)) return TRUE; //Check For/Assemble Pseudo-Op
if (asmswo()) return TRUE; //Check for/Assemble Sweet-16 Instruction
if (lkpopc(opclst) == FALSE) xerror("Invalid Mnemonic %s\n", mnmnc); if (lkpopc(opclst) == FALSE) xerror("Invalid Mnemonic %s\n", mnmnc);
if (debug) printf("Assembling Opcode Token 0x%02X, ", token); if (debug) printf("Assembling Opcode Token 0x%02X, ", token);
if (debug) printf("Addressing Mode Mask 0x%04X\n", amode); if (debug) printf("Addressing Mode Mask 0x%04X\n", amode);
skpspc(); skpspc();
if (amode == RELTV) asmbrn(TRUE); //Branch (Relative) Instruction if (amode == RELTV) asmbrn(TRUE); //Branch (Relative) Instruction
else if (amode == 0x0004 || amode == 0x1004) asmzpr(); //Branch (Relative) Instruction else if (amode == 0x0004 || amode == 0x1004) asmzpr(); //Branch ZP (Relative)
else if (cpychr('#')) asmimd(); //Assemble Implied Instruction else if (cpychr('#')) asmimd(); //Assemble Immediate Instruction
else if (cpychr('(')) asmind(); //Assemble Indirect Instruction else if (cpychr('(')) asmind(); //Assemble Indirect Instruction
else asmiaz(); //Assemble Implied/Accumulator/Absolute/ZeroPage Instruction else asmiaz(); //Assemble Implied/Accumulator/Absolute/ZeroPage Instruction
if (debug) dbgopc(); if (debug) dbgopc();
@ -685,6 +856,13 @@ void clsinc(void) {
endasm = FALSE; //Clear End Flag for Return to Main File endasm = FALSE; //Clear End Flag for Return to Main File
} }
/* Close Object File */
void clsobj() {
if (objbin) {if (objtyp == ATRFIL) atrend();}
else {if (objcnt) outeot();}
fclose(outfil);
}
/* Assemble Input File (Two Pass) * /* Assemble Input File (Two Pass) *
* Args: pass - Assembly Pass (1 or 2) * * Args: pass - Assembly Pass (1 or 2) *
* Requires: inpfil - Input File Pointer * * Requires: inpfil - Input File Pointer *
@ -699,6 +877,8 @@ void asmfil(int pass) {
blknum = 0; // and Local Block Number blknum = 0; // and Local Block Number
orgadr = -1; //Origin Address Not Set orgadr = -1; //Origin Address Not Set
curadr = orgadr; //Set Current Address to Origin curadr = orgadr; //Set Current Address to Origin
exeadr = -1; //Execution Address Not Set
objcnt = 0; //Initialize Object File Byte Count
if (debug) printf("Rewinding Input File\n"); if (debug) printf("Rewinding Input File\n");
rewind(inpfil); //Start at Beginning of Input File rewind(inpfil); //Start at Beginning of Input File
while (TRUE) { while (TRUE) {
@ -720,6 +900,8 @@ void asmfil(int pass) {
lineno++; lineno++;
if (incnam[0] && incfil == NULL) opninc(); //Open Include File if (incnam[0] && incfil == NULL) opninc(); //Open Include File
} }
endadr = curadr; //Set End Address for Second Pass
if (debug) printf("End address set to %04x\n", endadr);
} }
/* Parse Command Line Option */ /* Parse Command Line Option */
@ -729,9 +911,14 @@ int pcoptn(char *argval) {
if (debug) printf(" Option '%c'\n", option); if (debug) printf(" Option '%c'\n", option);
switch(option) { switch(option) {
case 'D': debug = TRUE; break; //Enable debug Output case 'D': debug = TRUE; break; //Enable debug Output
case 'A': objtyp = APLFIL; break; //Apple-1 Monitor Entry File
case 'E': objtyp = ATRFIL; break; //Atari 8-Bit EXE File
case 'P': objtyp = PRGFIL; break; //Commodore PRG File case 'P': objtyp = PRGFIL; break; //Commodore PRG File
case 'S': objtyp = MSRFIL; break; //Motorola SREC File
case 'X': objtyp = INTFIL; break; //Intel HEX File
default: xerror("Illegal Command Line Option %s\n", argval); default: xerror("Illegal Command Line Option %s\n", argval);
} }
if (debug && objtyp) printf("Object type set to %d\n", objtyp);
return TRUE; return TRUE;
} }
@ -766,12 +953,13 @@ int main(int argc, char *argv[]) {
objtyp = BINFIL; //Default Object File Type to Binary objtyp = BINFIL; //Default Object File Type to Binary
pcargs(argc, argv); //Parse Command Line Arguments pcargs(argc, argv); //Parse Command Line Arguments
inpfil = opnfil(inpnam, "r", ""); //Open Input File inpfil = opnfil(inpnam, "r", ""); //Open Input File
outfil = opnfil(outnam, "wb", ""); //Open Output File outfil = opnobj(outnam, ""); //Open Output File
if (lstnam[0]) //If List File Name Specified if (lstnam[0]) //If List File Name Specified
lstfil = opnfil(lstnam, "w", ""); // Open List File lstfil = opnfil(lstnam, "w", ""); // Open List File
asmfil(1); //Assemble Input File (First Pass) asmfil(1); //Assemble Input File (First Pass)
asmfil(2); //Assemble Input File (First Pass) asmfil(2); //Assemble Input File (First Pass)
if (lstfil && symcnt) prtsym(); //Print Symbol Table if (lstfil && symcnt) prtsym(); //Print Symbol Table
clsobj(); //Close Object File
exit(0); //Exit with No Errors exit(0); //Exit with No Errors
} }

33
a02.h
View File

@ -4,15 +4,18 @@
#define MAXLBL 8 //Maximum Symbol Length #define MAXLBL 8 //Maximum Symbol Length
#define MAXSYM 1024 //Maximum Number of Labels #define MAXSYM 1024 //Maximum Number of Labels
//#define NULL &0
#define FALSE 0 #define FALSE 0
#define TRUE -1 #define TRUE -1
/* Address Mode Bit Masks */ /* Address Mode Bit Masks */
#define RGSTR 0x0000 //Register (Sweet 16)
#define ACMLT 0x0001 //Accumulator [$xA] #define ACMLT 0x0001 //Accumulator [$xA]
#define IMMDT 0x0002 //*Immediate [w/Acc] #define IMMDT 0x0002 //*Immediate [w/Acc]
#define ZPAGE 0x0004 //Zero Page #define ZPAGE 0x0004 //Zero Page
#define ZPAGX 0x0008 //*Zero Page,X #define ZPAGX 0x0008 //*Zero Page,X
//#define ZPAGY 0x0010 //*Zero Page,Y [By OpCodes] #define RGIND 0x0010 //Register or Imderect (Sweet 16)
#define ABSLT 0x0020 //Absolute #define ABSLT 0x0020 //Absolute
#define ABSLX 0x0040 //*Absolute,X [fixops()] #define ABSLX 0x0040 //*Absolute,X [fixops()]
#define ABSLY 0x0080 //Absolute,Y #define ABSLY 0x0080 //Absolute,Y
@ -24,13 +27,15 @@
char zpgabs[][9] = {"Absolute", "ZeroPage"}; char zpgabs[][9] = {"Absolute", "ZeroPage"};
/* Address Mode Descriptions */
struct amd {int amode; char desc[12];}; struct amd {int amode; char desc[12];};
struct amd amdesc[] = { struct amd amdesc[] = {
{ACMLT, "Accumulator"}, {ACMLT, "Accumulator"},
{IMMDT, "Immediate"}, {IMMDT, "Immediate"},
{ZPAGE, "Zero Page"}, {ZPAGE, "Zero Page"},
{ZPAGX, "Zero Page,X"}, {ZPAGX, "Zero Page,X"},
{ABSLT, "Absolute"}, {ABSLT, "Absolute"},
{RGSTR, "Register"},
{ABSLX, "Absolute,X"}, {ABSLX, "Absolute,X"},
{ABSLY, "Absolute,Y"}, {ABSLY, "Absolute,Y"},
{IMPLD, "Implied"}, {IMPLD, "Implied"},
@ -45,7 +50,8 @@ struct opc {char name[5], token; int amode;};
struct opc psolst[] = { struct opc psolst[] = {
{"BYTE", 'B', 0}, {"HEX", 'H'}, {"WORD", 'W', 0}, {"EQU", '=', 0}, {"FILL", 'F', 0}, {"BYTE", 'B', 0}, {"HEX", 'H'}, {"WORD", 'W', 0}, {"EQU", '=', 0}, {"FILL", 'F', 0},
{"INCL", 'I', 0}, {"SUBR", 'S', 0}, {"DC", 'B', 0}, {"DS", 'F', 0}, {"ALIG", 'A', 0}, {"INCL", 'I', 0}, {"SUBR", 'S', 0}, {"DC", 'B', 0}, {"DS", 'F', 0}, {"ALIG", 'A', 0},
{"ORG", '*', 0}, {"PROC", 'P', 0}, {"END", 'E', 0}, {"ENDS", 'M', 0}, {"", 0, 0} {"ORG", '*', 0}, {"PROC", 'P', 0}, {"END", 'E', 0}, {"ENDS", 'M', 0}, {"EXEC", 'X', 0},
{"DW", 'W', 0}, {"", 0, 0}
}; };
struct opc opclst[] = { struct opc opclst[] = {
@ -73,7 +79,7 @@ struct opc opclst[] = {
{"RMB4", 0x47, 0x0004}, {"RMB5", 0x57, 0x0004}, {"RMB6", 0x67, 0x0004}, {"RMB7", 0x77, 0x0004}, {"RMB4", 0x47, 0x0004}, {"RMB5", 0x57, 0x0004}, {"RMB6", 0x67, 0x0004}, {"RMB7", 0x77, 0x0004},
{"SMB0", 0x87, 0x0004}, {"SMB1", 0x97, 0x0004}, {"SMB2", 0xA7, 0x0004}, {"SMB3", 0xB7, 0x0004}, {"SMB0", 0x87, 0x0004}, {"SMB1", 0x97, 0x0004}, {"SMB2", 0xA7, 0x0004}, {"SMB3", 0xB7, 0x0004},
{"SMB4", 0xC7, 0x0004}, {"SMB5", 0xD7, 0x0004}, {"SMB6", 0xE7, 0x0004}, {"SMB7", 0xF7, 0x0004}, {"SMB4", 0xC7, 0x0004}, {"SMB5", 0xD7, 0x0004}, {"SMB6", 0xE7, 0x0004}, {"SMB7", 0xF7, 0x0004},
{"RMB", 0x07, 0x0004}, {"SMB", 0x87, 0x0004}, {"RMB", 0x07, 0x0004}, {"SMB", 0x87, 0x0004},
{"BBR0", 0x0F, 0x1004}, {"BBR1", 0x1F, 0x1004}, {"BBR2", 0x2F, 0x1004}, {"BBR3", 0x3F, 0x1004}, {"BBR0", 0x0F, 0x1004}, {"BBR1", 0x1F, 0x1004}, {"BBR2", 0x2F, 0x1004}, {"BBR3", 0x3F, 0x1004},
{"BBR4", 0x4F, 0x1004}, {"BBR5", 0x5F, 0x1004}, {"BBR6", 0x6F, 0x1004}, {"BBR7", 0x7F, 0x1004}, {"BBR4", 0x4F, 0x1004}, {"BBR5", 0x5F, 0x1004}, {"BBR6", 0x6F, 0x1004}, {"BBR7", 0x7F, 0x1004},
@ -113,3 +119,22 @@ struct opf opfix[] = {
{0,0,0} {0,0,0}
}; };
/* Sweet 16 Address Modes
IMPLD - Implied (No Argument)
RGSTR - Register
INDCT - Register Indirect
ABSLT - Register Absolute
RKLTV - Relative (Branch)
RGIND - Register or Indirect
*/
/* Sweet 16 OpCodes */
struct opc swolst[] = {
{"RTN", 0x00, IMPLD}, {"BR", 0x01, RELTV}, {"BNC", 0x02, RELTV}, {"BC", 0x03, RELTV},
{"BP", 0x04, RELTV}, {"BM", 0x05, RELTV}, {"BZ", 0x06, RELTV}, {"BNZ", 0x07, RELTV},
{"BM1", 0x08, RELTV}, {"BNM1", 0x09, RELTV}, {"BK", 0x0A, IMPLD}, {"RS", 0x0B, IMPLD},
{"BS", 0x0C, RELTV}, {"SET", 0x10, ABSLT}, {"LD", 0x20, RGIND}, {"ST", 0x30, RGIND},
{"LD", 0x40, INDCT}, {"ST", 0x50, INDCT}, {"LDD", 0x60, INDCT}, {"STD", 0x70, INDCT},
{"POP", 0x80, INDCT}, {"STP", 0x90, INDCT}, {"ADD", 0xA0, RGSTR}, {"SUB", 0xB0, RGSTR},
{"POPD", 0xC0, INDCT}, {"CPR", 0xD0, RGSTR}, {"INR", 0xE0, RGSTR}, {"DCR", 0xF0, RGSTR}
};

View File

@ -1,11 +1,32 @@
; C02 module intlib.h02 assembly language subroutines ; C02 module intlib.h02 assembly language subroutines
; Requires ; Requires external zero page words DSTPTR, SRCPTR,
; external zero page words DSTPTR and SRCPTR ; external bytes TEMP0, TEMP1, TEMP2, and TEMP3, and
; and external locations TEMP0, TEMP1, TEMP2, and TEMP3 ; external words INTACC, INTARG, and INTOVR.
SUBROUTINE INTLIB SUBROUTINE INTLIB
;iabs(n) - Get Integer ABSolute Value ;iacc(i) - Set Integer Accumulator to i
;Args: Y,X = Argument
;Sets: INTACC = Y,X
IACC: STX INTACC
STY INTACC+1
RTS
;Set Integer Argument
.SETARG STX INTARG
STY INTARG+1
RTS
;Clear Integer Overflow
;Sets: INTOVR = 0
;Returns A = 0
.CLROVR LDA #0
STA INTOVR
STA INTOVR+1
RTS
;iabs(i) - Get Integer ABSolute Value
;Args: Y,X = Integer to get Absolute Value Of ;Args: Y,X = Integer to get Absolute Value Of
;Sets: TEMP1, TEMP2 ;Sets: TEMP1, TEMP2
;Affects: C, N, Z ;Affects: C, N, Z
@ -23,188 +44,248 @@ IABS: CPY #$80 ;If Negative (High Bit Set)
;imax(i) - Get MAXimum of Two Integers ;imax(i) - Get MAXimum of Two Integers
;Args: Y,X = Second Integer ;Args: Y,X = Second Integer
;Uses: SRCPTR = First Integer ;Uses: INTACC = First Integer
;Affects: N,Z,C ;Affects: N,Z,C
;Returns: Y,X = Larger of the Two Arguments ;Returns: Y,X = Larger of the Two Arguments
IMAX: CPY SRCPTR+1 ;If Y < SRCPTR MSB IMAX: CPY INTACC+1 ;If Y < INTACC MSB
BCC .GETSRC ; Return SRCPTR BCC .GETACC ; Return INTACC
CPX SRCPTR ;IF X >= SRCPTR LSB CPX INTACC ;IF X >= INTACC LSB
BCS .RETURN ; Return Argument BCS .IMSET ; Set INTACC to and Return Argument
.GETSRC JMP GETSRC ;Return Integer in SRCPTR .GETACC LDX INTACC ;Return Integer Accumulator
LDY INTACC+1
RTS
;imin(i) - Get MINimum of Two Integers ;imin(i) - Get MINimum of Two Integers
;Args: Y,X = Second Integer ;Args: Y,X = Second Integer
;Uses: SRCPTR = First Integer ;Uses: INTACC = First Integer
;Sets: IINTACC = Result
;Affects: N,Z,C ;Affects: N,Z,C
;Returns: Y,X = Larger of the Two Arguments ;Returns: Y,X = Larger of the Two Arguments
IMIN: CPY SRCPTR+1 ;If Y < SRCPTR+1 IMIN: CPY INTACC+1 ;If Y < INTACC+1
BCC .RETURN ; Return Argument BCC .RETURN ; Return Argument
BNE .GETSRC ;If Y > SRCPTR+1 Return SRCPTR BNE .GETACC ;If Y > INTACC+1
CPX SRCPTR ;If X >= SRCPTR CPX INTACC ;or X >= INTACC
BCS .GETSRC ; Return SRCPTR BCS .GETACC ; Return INTACC
RTS ;Return Argument .IMSET JMP IACC ;Else Set INTACC to and Return Argument
;iaddc(c,i) - Add Byte c to Integer i ;iaddc(c,i) - Integer ADD Char c to int i
IADDC: JSR SETSRC ;Save Integer and Clear Y IADDC: JSR IACC ;Store Integer in Accumulator
LDY #0 ;Set Argument MSB to 0
TAX ;Copy Byte to LSB and drop into IADD TAX ;Copy Byte to LSB and drop into IADD
;iadd(d) - ADD Integer d to from Integer g ;iand(d) - Integer ADD g + d
;Args: Y,X = Addend ;Args: Y,X = Addend
;Requires: setsrc(g) - Augend ;Requires: IACC(g) - Augend
;Sets: TEMP1,TEMP2 = Addend ;Sets: INTACC = Result
;Affects: Z,C ;Affects: Z
;Returns: A = Carry ;Returns: Y,X = Sum
;IAND: TXA ;AND Argument LSB
; AND IACC ;with Accumulator LSB
; TAX
; TYA ;AND Argument MSB
; AND IACC+1 ;with Accumulator MSB
; TAY
; JMP IACC ;Set INTACC to And Return Result
;iadd(d) - Integer ADD g + d
;Args: Y,X = Addend
;Requires: IACC(g) - Augend
;Sets: INTACC = Sum
;Affects: Z
;Returns: A,C = Carry
; Y,X = Sum ; Y,X = Sum
; N = Sign of Result ; N = Sign of Result
IADD: CLC ;Clear Carry for Addition IADD: CLC ;Clear Carry for Addition
TXA ;Add Addend LSB TXA ;Add Addend LSB
ADC SRCPTR ;to Augend LSB ADC INTACC ;to Augend LSB
TAX ;and Copy to X TAX ;and Copy to X
TYA ;Add Addend MSB TYA ;Add Addend MSB
ADC SRCPTR+1 ;to Augebd MSB ADC INTACC+1 ;to Augebd MSB
TAY ;and Copy to Y TAY ;and Copy to Y
LDA #0 ;Set Overflow to 0 PHP ;Save Result Flags
ROL ; Rotate Carry (Same as Adding it) LDA #0 ;Clear CHR Result to 0
RTS ; and Return STA INTOVR+1 ; and Clear Overflow MSB
ROL ;Rotate Carry Flag into CHR Result
STA INTOVR ; and store in INTOVR
PLP ;Restore Result Flags
JMP IACC ;Set INTACC to And Return Result
;isub(s) - SUBtract Integer s from Integer m ;ineg(i) - Integer NEGate int i
;Args: Y,X = Integer to Negate
;Sets: INTACC = Result
; INTARG = Argument
;Returns: Y,X = Negated Integer
; N = Sign of Result
INEG: LDA #0 ;Set Minuend to Zero
STA INTACC
STA INTACC+1
;isub(s) - Integer SUBtract m - s
;Args: Y,X = Subtrahend ;Args: Y,X = Subtrahend
;Requires: setsrc(m) - Minuend ;Requires: IACC(m) - Minuend
;Sets: TEMP1,TEMP2 = Subtrahend ;Sets: INTACC = Difference
;Affects: Z,C ; INTARG = Subtrahend
;Returns: A = Carry ;Affects: Z
;Returns: A,C = Carry
; Y,X = Difference ; Y,X = Difference
; N = Sign of Result ; N = Sign of Result
ISUB: JSR SAVRXY ;Store Subtrahend in TEMP1,TEMP2 ISUB: JSR .SETARG ;Store Subtrahend in INTARG
SEC ;Set Carry for Subtraction SEC ;Set Carry for Subtraction
LDA SRCPTR ;Load Minuend LSB LDA INTACC ;Load Minuend LSB
SBC TEMP1 ;Subtract Subtrahend LSB SBC INTARG ;Subtract Subtrahend LSB
TAX ;Copy Difference LSB to X TAX ;Copy Difference LSB to X
LDA SRCPTR+1 ;Load Minuend MSB LDA INTACC+1 ;Load Minuend MSB
SBC TEMP2 ;Subtract Subtrahend MSB SBC INTARG+1 ;Subtract Subtrahend MSB
TAY ;Copy Difference MSB to Y TAY ;Copy Difference MSB to Y
LDA #0 ;Set Overflow Byte to 0 PHP ;Save Result Flags
SBC #0 ; Subtract Carry LDA #0 ;Set Overflow Byte to 0
RTS ; and Return SBC #0 ;and Subtract Carry
PLP ;Restore Result Flags
JMP IACC ;Set INTACC to And Return Result
;imultc(c,m) - Multiply Int m by Char c
;Args: A - Multiplicand
; Y,X - Multiplier
;Sets: INTACC - Product MSB, LSB
IMULTC: STA INTACC ;Set Integer Accumulator to int(A)
LDA #0
STA INTACC+1 ;and execute IMULT
;imult(m) - MULTiply Two Integers ;imult(m) = MULTiply Integer n * Integer m
;Args: Y,X - Multiplier ;Args: Y,X = Multiplier
;Requires: DSTPTR = Multiplicand ;Uses: INTACC = Multiplicand
;Sets: TEMP0-TEMP3 = 32 Bit Product ;Sets: INTACC = Product MSB, LSB
;Destroys: SRCPTR ;Sets: INTOVR = Product MSB, LSB
;Affects: A,C,Z,N ;Destroys: TEMP0,TEMP1,TEMP2,TEMP3
;Affects: C,Z,N
;Returns: A,Y,X = 24 Bit Product ;Returns: A,Y,X = 24 Bit Product
IMULT: JSR SETSRC ;Save Multiplier IMULT: JSR .SETARG ;Save Multiplier
STY TEMP0+2 ;Clear Upper Bits of Product LDY #0
STY TEMP0+3 STY INTOVR ;Clear Upper Bits of Product
STY INTOVR+1
LDX #16 ;Rotate Through 16 Bits LDX #16 ;Rotate Through 16 Bits
.MSHFTR LSR SRCPTR+1 ;Divide Multiplier by 2 .MSHFTR LSR INTARG+1 ;Divide Multiplier by 2
ROR SRCPTR ROR INTARG
BCC .MROTR ;If Shifted out Bit is 1 BCC .MROTR ;If Shifted out Bit is 1
LDA TEMP0+2 ; Add Multiplicand LDA INTACC ; Add Multiplicand
CLC ; to Upper Half of Product CLC ; to Upper Half of Product
ADC DSTPTR ADC INTOVR
STA TEMP0+2 STA INTOVR
LDA TEMP0+3 LDA INTOVR+1
ADC DSTPTR+1 ADC INTACC+1
STA TEMP0+3 STA INTOVR+1
.MROTR ROR TEMP0+3 .MROTR ROR INTOVR+1
ROR TEMP0+2 ROR INTOVR
ROR TEMP0+1 ROR TEMP1
ROR TEMP0 ROR TEMP0
DEX ;Decrement Counter DEX ;Decrement Counter
BNE .MSHFTR ;and Process Next Bit BNE .MSHFTR ;and Process Next Bit
LDX TEMP0 LDA INTOVR ;Get Bits 16-24 of Result
LDY TEMP1 ;Return Low 24 Bits of LDY TEMP1 ;Get Bits 8-15 of Result
LDA TEMP2 ;Product in A, Y, and X LDX TEMP0 ;Get Bits 0-7 of Result
RTS JMP IACC ;Store Y,X in INTACC and Return in Y,X
;idiv(d) - Integer DIVide ;imod(d) - Integer MODulus d % s
;Args: Y,X - Divisor ;Args: Y,X - Divisor
;Requires: DSTPTR = Dividend ;Requires: IACC(d) = Dividend
;Sets: SRCPTR = Divisor ;Sets: INTARG = Divisor
; DSTPTR = Quotient ; INTACC, INTOVR = Modulus
; TEMP1,TEMP2 = Remainder ;Affects: A,C,Z,N
;Returns: Y,X = 16 Bit Modulus
IMOD: JSR IDIV ;Do Division
LDX INTOVR ;get Remainder
LDY INTOVR+1 l
JMP IACC ;Store in INTACC and Return in Y,X
;idiv(s) - Integer DIVide d / s
;Args: Y,X - Divisor
;Requires: IACC(d) = Dividend
;Sets: INTARG = Divisor
; INTACC = Quotient
; INTOVR = Remainder
;Affects: A,C,Z,N ;Affects: A,C,Z,N
;Returns: Y,X = 16 Bit Quotient ;Returns: Y,X = 16 Bit Quotient
IDIV: JSR .IDIV ;Do Division and IDIV: JSR .SETARG ;Save Divisor
JMP GETDST ;Return Quotient LDY #0
STY INTOVR
;imod(d) - Integer MODulus STY INTOVR+1
;Args: Y,X - Divisor
;Requires: DSTPTR = Dividend
;Sets: SRCPTR = Divisor
; DSTPTR = Quotient
; TEMP1,TEMP2 = Remainder
;Affects: A,C,Z,N
;Returns: Y,X = 16 Bit Remainder
IMOD: JSR .IDIV ;Do Division and
JMP RESRXY ;Return Remainder
.IDIV JSR SETSRC ;Save Divisor
STY TEMP1
STY TEMP1+1
LDX #16 ;repeat for each bit: ... LDX #16 ;repeat for each bit: ...
.IDLOOP ASL DSTPTR ;dividend lb & hb*2, msb -> Carry .IDLOOP ASL INTACC ;dividend lb & hb*2, msb -> Carry
ROL DSTPTR+1 ROL INTACC+1
ROL TEMP1 ;remainder lb & hb * 2 + msb from carry ROL INTOVR ;remainder lb & hb * 2 + msb from carry
ROL TEMP1+1 ROL INTOVR+1
LDA TEMP1 LDA INTOVR
SEC SEC
SBC SRCPTR ;subtract divisor to see if it fits in SBC INTARG ;subtract divisor to see if it fits in
TAY ;lb result -> Y, for we may need it later TAY ;lb result -> Y, for we may need it later
LDA TEMP1+1 LDA INTOVR+1
SBC SRCPTR+1 SBC INTARG+1
BCC .IDSKIP ;if carry=0 then divisor didn't fit in yet BCC .IDSKIP ;if carry=0 then divisor didn't fit in yet
STA TEMP1+1 ;else save substraction result as new remainder, STA INTOVR+1 ;else save substraction result as new remainder,
STY TEMP1 STY INTOVR
INC DSTPTR ;and INCrement result cause divisor fit in 1 times INC INTACC ;and INCrement result cause divisor fit in 1 times
.IDSKIP DEX .IDSKIP DEX
BNE .IDLOOP BNE .IDLOOP
RTS JMP .GETACC ;Return Integer Accumulator
;ishftl(n,i) - Shift Integer i to the Left n Bits ;ishftl(n,i) - Shift Integer i to the Left n Bits
;Sets: TEMP1, TEMP2 = LSB, MSB of Result ;Args: A = Number of Bits to Shift
;Affects: A,Y,N,Z,C ; Y,X = Integer Value to Shift
;Returns: A = Bits Shifted out of Integer ;Sets: INTACC = Bits 0 to 15 of Result
; INTOVR = Bits 16 to 31 of Result
;Sets: INTACC = Shifted Intger
;Affects: N,Z,C
;Returns: A = LSB of Underflow
; Y,X = Shifted Integer ; Y,X = Shifted Integer
ISHFTL: JSR SAVRXY ;Save X,Y in TEMP1,TEMP2 ISHFTL: JSR IACC ;Save Argument in INTACC
TAY ;Set Counter to Number of Bits LDX #0 ;Clear Overflow
BEQ .RESRXY ;If Zero, Return STX INTOVR
LDA #0 ;Clear Overflow STX INTOVR
.LSLOOP ASL TEMP1 ;Shift LSB to Left TAX ;Set Counter to Number of Bits
ROL TEMP2 ;Rotate MSB to Left BEQ .LSDONE ;If Zero, Return 0
ROL ;Rotate Carry into A .LSLOOP ASL INTACC ;Shift Bits 0-7 to Left
DEY ;Decrement Counter ROL INTACC+1 ;Rotate Bits 8-15 to Left
ROL INTOVR ;Rotate Bits 16-23 to Left
ROL INTOVR+1 ;Rotate Bits 24-31 to Left
DEX ;Decrement Counter
BNE .LSLOOP ; and Loop if Not 0 BNE .LSLOOP ; and Loop if Not 0
BEQ .RESRXY ;Return Shifted Integer LDA INTOVR ;Return Bits 16-23 in A
.LSDONE JMP .GETACC ;and Bits 0-15 in Y,X
;ishftr(n,i) - Shift Integer i to the Right n Bits ;ishftr(n,i) - Shift Integer i to the Right n Bits
;Sets: TEMP1, TEMP2 = LSB, MSB of Result ;Args: A = Number of Bits to Shift
;Affects: A,Y,N,Z,C ; Y,X = Integer Value to Shift
;Returns: A = Bits Shifted out of Integer ;Sets: INTACC = Bits 0 to 15 of Result
; Y,X = Shifted Integer ; INTOVR = Bits -1 to -16 of Result
ISHFTR: JSR SAVRXY ;Save X,Y in TEMP1,TEMP2 ;Sets: INTACC = Shifted Intger
TAY ;Set Counter to Number of Bits ;Affects: N,Z,C
BEQ .RESRXY ;If Zero, Return ;Returns: A = MSB of Underflow
LDA #0 ;Clear Overflow ; Y,X = Shifted Result
.RSLOOP LSR TEMP2 ;Shift MSB to Right ISHFTR: JSR IACC ;Save Argument in INTACC
ROR TEMP1 ;Rotate LSB to Right LDX #0 ;Clear Overflow
ROR ;Rotate Carry into A STX INTOVR
DEY ;Decrement Counter STX INTOVR
TAX ;Set Counter to Number of Bits
BEQ .RSDONE ;If Zero, Return Argument
.RSLOOP LSR INTACC+1 ;Shift MSB to Right
ROR INTACC ;Rotate LSB to Right
ROR INTOVR+1 ;Rotate Underflow MSB
ROR INTOVR ;Rotate Underflow LSB
DEX ;Decrement Counter
BNE .RSLOOP ; and Loop if Not 0 BNE .RSLOOP ; and Loop if Not 0
BEQ .RESRXY ;Load Shifted Integer and Return LDA INTOVR+1 ;Return Underflow MSB in A
.RSDONE JMP .GETACC ;and Result in Y,X
;atoi(&s) - ASCII string TO Integer ;atoi(&s) - ASCII string TO Integer
;Args: Y,X = Address of String to Convert ;Args: Y,X = Address of String to Convert
;Sets: TEMP1, TEMP2 = Integer Value ;Sets: INTACC = Integer Value
;Affects: TEMP0 ;Affects: TEMP0,TEMP1,TEMP2
;Returns: A = Number of Digits ;Returns: A = Number of Digits
; Y,X = Integer Value ; Y,X = Integer Value
ATOI: JSR SETSRC ;Initialize Source String ATOI: JSR SETSRC ;Initialize Source String
STY TEMP1 ;Initialize Result STY TEMP1 ;Initialize Result
STY TEMP2 STY TEMP2
.AILOOP LDA (SRCPTR),Y ;Get Next Character .AILOOP LDA (SRCPTR),Y ;Get Next Character
CMP #$30 ;If Less Than '0' CMP #$30 ;If Less Than '0'
BCC .AIDONE ; Exit BCC .AIDONE ; Exit
CMP #$3A ;If Greater Than '9' CMP #$3A ;If Greater Than '9'
@ -235,14 +316,18 @@ ATOI: JSR SETSRC ;Initialize Source String
INY ;Increment Index INY ;Increment Index
BPL .AILOOP ; and Loop BPL .AILOOP ; and Loop
.AIDONE TYA ;Return Number of Digits .AIDONE TYA ;Return Number of Digits
.RESRXY JMP RESRXY ;and Integer Value .RESRXY JSR RESRXY ;and Integer Value
JMP IACC
;itoa(n) - Integer TO ASCII string ;itoa(&d) - Integer TO ASCII string
;Args: Y,X = Integer Value to Convert ;Args: Y,X = Address of Destination String
;Uses: INTACC = Integer to Convert
;Uses: DSTPTR = Destination String ;Uses: DSTPTR = Destination String
;Affects: X ;Affects: X
;Returns: A,Y = Length of String ;Returns: A,Y = Length of String
ITOA: JSR CVIBCD ;Convert Integer to Packed BCD ITOA: JSR SETDST ;Store String Pointer Agrumenr
JSR .GETACC ;Load INTACC
JSR CVIBCD ;Convert Integer to Packed BCD
LDY #0 ;Initialize Index into String LDY #0 ;Initialize Index into String
STY TEMP3 STY TEMP3
.ITOAA LDY #4 ;Set Initial Digit Number .ITOAA LDY #4 ;Set Initial Digit Number
@ -250,24 +335,25 @@ ITOA: JSR CVIBCD ;Convert Integer to Packed BCD
BNE .IASKIP ;If Zero BNE .IASKIP ;If Zero
DEY ; Decrement Digit Number DEY ; Decrement Digit Number
BNE .IAZERO ; If Not Zero Loop BNE .IAZERO ; If Not Zero Loop
BEQ .IASKIP ; Else .IDSKIP Unpack BEQ .IASKIP ; Else Branch into .IALOOP
.IALOOP JSR UPBCDI ;Unpack Digit #Y .IALOOP JSR UPBCDI ;Unpack Digit #Y
.IASKIP TAX ;Save Digit in X .IASKIP TAX ;Save Digit in X
TYA ;Push Digit Number into Stack TYA ;Push Unpack Index into Stack
PHA PHA
TXA ;and Restore Digit TXA ;and Restore Digit
LDY TEMP3 ;Get Index into String
ORA #$30 ;Convert Digit to ASCII ORA #$30 ;Convert Digit to ASCII
LDY TEMP3 ;Get Index into String
STA (DSTPTR),Y ;and Store in String STA (DSTPTR),Y ;and Store in String
INC TEMP3 ;Increment Index into String INC TEMP3 ;Increment Index into String
PLA ;Pull Digit Number off Stack PLA ;Pull Digit Number off Stack
TAY TAY
DEY ;Decrement Digit Number DEY ;Decrement Digit Number
BPL .IALOOP ;Loop if >= Zero BPL .IALOOP ;Loop if >= Zero
LDA #0 ;Terminate String LDA #0 ;Terminate String
STA (DSTPTR),Y STA (DSTPTR),Y
TYA ;Return String Length TYA ;Return String Length
RTS JMP .GETACC ;and INTACC
;upbcdi() - UnPack digits from BCD Integer ;upbcdi() - UnPack digits from BCD Integer
; Assumes that TEMP0, TEMP1, and TEMP2 ; Assumes that TEMP0, TEMP1, and TEMP2
@ -298,21 +384,17 @@ UPBCDI: PHP
; TEMP1 = Thousands and Hundreds Digit ; TEMP1 = Thousands and Hundreds Digit
; TEMP2 = Ten-Thousands Digit ; TEMP2 = Ten-Thousands Digit
;Affects: A ;Affects: A
CVIBCD: LDA #0 ;Clear BCD Bytes CVIBCD: JSR IACC ;Store Argument
LDA #0 ;Clear BCD Bytes
STA TEMP0 STA TEMP0
STA TEMP1 STA TEMP1
STA TEMP2 STA TEMP2
PHP ;Save Status Register PHP ;Save Status Register
SEI ;Disable Interrupts SEI ;Disable Interrupts
SED ;Set Decimal Mode SED ;Set Decimal Mode
TYA ;Push MSB onto Stack
PHA
TXA ;Push LSB onto Stack
PHA
TSX ;Copy Stack Pointer to X
LDY #16 ;Process 16 bits of Binary LDY #16 ;Process 16 bits of Binary
.CVLOOP ASL $101,X ;Shift High Bit Into Carry .CVLOOP ASL INTACC ;Shift High Bit Into Carry
ROL $102,X ROL INTACC+1
LDA TEMP0 ;Add 6 Digit BCD Number Itself LDA TEMP0 ;Add 6 Digit BCD Number Itself
ADC TEMP0 ; Effectively Multiplying It by 2 ADC TEMP0 ; Effectively Multiplying It by 2
STA TEMP0 ; and Adding in the Shifted Out Bit STA TEMP0 ; and Adding in the Shifted Out Bit
@ -324,9 +406,27 @@ CVIBCD: LDA #0 ;Clear BCD Bytes
STA TEMP2 STA TEMP2
DEY ;Decrement Counter and DEY ;Decrement Counter and
BNE .CVLOOP ; Process Next Bit BNE .CVLOOP ; Process Next Bit
PLA ;Restore X and Y Registers
PLA
PLP ;Restore Status Register PLP ;Restore Status Register
RTS RTS
;icmp(j) - Compare Int i to Int j
;Requires: IACC(i) - int to compare against
;Args: X,Y = int to compare
; N based on return value of A
;Returns A=$01 and C=1 if INTACC > Arg
; A=$00 and Z=1, C=1 if INTACC = Arg
; A=$FF and C=0 if INTACC < Arg
ICMP: CPY INTACC+1 ;Compare MSBs
BCC .GT ;INTACC < Y,X
BNE .LT ;INTACC > Y,X
CPX INTACC ;Compare LSBs
BCC .GT ;INTACC < Y,X
BNE .LT ;INTACC > Y,X
LDA #0
RTS ;Return INTACC = YX
.LT LDA #$FF
RTS ;Return INTACC < YX
.GT LDA #1
RTS ;Return INTACC > YX
ENDSUBROUTINE ENDSUBROUTINE

View File

@ -2,77 +2,115 @@
* intlib - Standard Library Routines for Integer Values * * intlib - Standard Library Routines for Integer Values *
*********************************************************/ *********************************************************/
/* Integer Absolute Value * /* Set Integer Accumlator *
* Args: int w - Integer to test * * Args: int w - Integer value *
* Returns: int v -Absolute value of w */ * Sets: iacc = Argument *
* Returns: int w - Argument */
char iacc();
/* Integer Absolute Value *
* Args: int w - Integer value *
* Sets: iacc = Result *
* Returns: int v - Absolute value of w */
char iabs(); char iabs();
/* Integer Add * /* Integer Add: g + d *
* Setup: setsrc(g) - Augend * * Setup: iset(g) - Augend *
* Args: int d - Addend * * Args: int d - Addend *
* Returns: char c - Carry * * Sets: iacc, iover = Result *
* int r - Sum */ * Returns: char c - Carry *
* int r - Sum */
char iadd(); char iadd();
/* Integer Add Char: c + d *
* Args: char c - Augend *
* int d - Addend *
* Sets: iacc, iover = result *
* Returns: char c - Carry *
* int r - Sum */
char iaddc();
/* ASCII to Integer * /* ASCII to Integer *
* Convert ASCII string to Unsigned Integer * * Convert ASCII string to Unsigned Integer *
* Args: &s - String to Convert * * Args: &s - String to Convert *
* Sets: iacc = Result *
* Returns: char n - Number of digits parsed * * Returns: char n - Number of digits parsed *
* int v - Numeric value of string */ * int v - Numeric value of string */
char atoi(); char atoi();
/* Integer to ASCII * /* Integer to ASCII *
* Convert Unsigned Integer to String * * Convert Unsigned Integer to String *
* Setup: setdst(s) - Destination String * * Setup: iset(i) - Unsigned Int to Convert *
* Args: int w - Unsigned Int to Convert * * Args: &s - Destination String *
* Returns: char n - Length of string */ * Sets: iacc = Argument *
* Returns: char n - Length of string */
void itoa(); void itoa();
/* Integer Divide * /* Integer unsigned Divide *
* Divide Unsigned Integers * * Aetup: iset (n) - Numerator *
* Aetup: setdst(n) - Numerator * * Args: int d - Denominator *
* Args: int d - Denominator * * Sets: iacc = Quotient *
* Returns: int q - Quotient */ * Returns: int q - Quotient */
char idiv(); char idiv();
/* Integer Maximum * /* Integer unsigned Maximum *
* Return Largest of Two Integers * * Return Largest of Two Integers *
* Requires: setsrc(i) - First Integer * * Setup: iset(i) - First Integer *
* Args: int j - Second Integer * * Args: int j - Second Integer *
* Sets: iacc = Result *
* Returns: int m - Greater of the Two */ * Returns: int m - Greater of the Two */
char imax(); char imax();
/* Integer Minimum * /* Integer unsigned Minimum *
* Return smallest of Two Integers * * Return smallest of Two Integers *
* Requires: setsrc(i) - First Integer * * Setup: setsrc(i) - First Integer *
* Args: int j - Second Integer * * Args: int j - Second Integer *
* Returns: int m - Lesser of the Two */ * Sets: iacc = Result *
* Returns: int m - Lesser of the Two */
char imin(); char imin();
/* Integer Multiply * /* Integer unsigned Modulo *
* Multiply Unsigned Integers * * Aetup: iset(n) - Numerator *
* Requires: setdst(m) - Muliplicand * * Args: int d - Denominator *
* Args: int r - Multiplier * * Sets: iacc = Result *
* Returns: long p - Product */ * Returns: int q - Modulus */
char idiv();
/* Integer unsigned Multiply: m * r *
* Setup: iset(m) - Muliplicand *
* Args: int r - Multiplier *
* Sets: iacc, iover = 32 bit Product *
* Returns: long p - 24 bit Product */
char imult(); char imult();
/* Integer Left Shift * /* Integer Multiply Char: c * r *
* Args: char n - Number of Bits * * Args: int c - Multplicand
* int w - Value to Shift * * int r - Multiplier *
* Returns: char v - Overflow Bits * * Sets: iacc, iover = 32 bit Product *
int r - Shifted Integer */ * Returns: long p - 24 bit Product */
char imult();
/* Integer Shift Left *
* Args: char n - Number of Bits *
* int w - Value to Shift *
* Sets: iacc = Integer result *
* iover = Integer Overflow *
* Returns: long p - 24 bit Result */
char ishftl(); char ishftl();
/* Integer Shift Right * /* Integer Shift Right *
* Args: char n - Number of Bits * * Args: char n - Number of Bits *
* int w - Value to Shift * * int w - Value to Shift *
* Returns: char v - Overflow Bits * * Sets: iacc = Integer result *
* iover = Integer Underflow *
* Returns: char u - Underflow Bits *
int r - Shifted Integer */ int r - Shifted Integer */
char ishftr(); char ishftr();
/* Integer Subtract * /* Integer Subtract: m - s *
* Requires: setsrc(m) - Minuend * * Setup: iaet(m) - Minuend *
* Args: int s - Subtrahend * * Args: int s - Subtrahend *
* Returns: char c - Carry * * Sets: iacc, iover = result *
* int d - Difference */ * Returns: char c - Carry *
* int d - Difference */
char isub(); char isub();

View File

@ -5,48 +5,70 @@ DELKEY EQU $08 ;Delete/Backspace Key (Backspace)
ESCKEY EQU $1B ;Escape/Stop Key (Escape) ESCKEY EQU $1B ;Escape/Stop Key (Escape)
RTNKEY EQU $0D ;Return/Enter Key (Carriage Return) RTNKEY EQU $0D ;Return/Enter Key (Carriage Return)
;Zero Page Locations ;Zero Page Variables
SRCPTR EQU $30 ;Source String Pointer ; $00-$06 ;Reserved
DSTPTR EQU $32 ;Destination String Pointer
BLKPTR EQU $34 ;Block Segment Pointer
STKPTR EQU $36 ;Stack Pointer
USRPTR EQU $38 ;User Pointer
XMADDR EQU $3A ;Extended Memory Address XMBANK EQU $07 ;Extended Memory Bank
XMBANK EQU $3C ;Extended Memory Bank XMADDR EQU $08 ;Extended Memory Address
; $3D ;Unused
RDSEED EQU $3E ;Pseudo-RANDOM Seed SRCPTR EQU $10 ;Source Pointer
RANDOM EQU $3F ;Pseudo-RANDOM Number Storage DSTPTR EQU $12 ;Destination Pointer
TEMP0 EQU $40 ;Temporary Storage TEMP0 EQU $14 ;Temporary Storage
TEMP1 EQU $41 TEMP1 EQU $15
TEMP2 EQU $42 TEMP2 EQU $16
TEMP3 EQU $43 TEMP3 EQU $17
TMPPTR EQU $44 ;Temporary Pointer TMPPTR EQU $18 ;Temporary Pointer
BLKBGN EQU $46 LSTPTR EQU $1A ;List Pointer
BLKEND EQU $48 USRPTR EQU $1C ;User Pointer
BLKLEN EQU $4A ;Block Segment Length ; $1E ;Reserved
SYSBFP EQU $4B ;Position in System Buffer
STKBGN EQU $4C ;Stack Start Address BLKLEN EQU $1F ;Block Segment Length
STKEND EQU $4E ;Stack End Address BLKPTR EQU $20 ;Block Segment Pointer
; $50-$FF ;Free Zero Page for Applications BLKBGN EQU $22 ;Block Start Address
BLKEND EQU $24 ;Block End Address
STKPTR EQU $26 ;Stack Pointer
STKBGN EQU $28 ;Stack Start Addres
STKEND EQU $2A ;Stack End Address
RDSEED EQU $2C ;Pseudo-RANDOM Seed
RANDOM EQU $2D ;Pseudo-RANDOM Number Storage
SYSBFP EQU $2E ;Position in System Buffer
.STKSAV EQU $2F ;Stack Pointer Storage
INTACC EQU $30 ;Integer Accumulator
INTOVR EQU $32 ;Integer Overflow
INTARG EQU $34 ;Integer Argument
; $34-$3F ;Reserved
; $40-$FF ;Free Zero Page for Applications
SYSBFL EQU 128 ;System Buffer Size (Max String Size) SYSBFL EQU 128 ;System Buffer Size (Max String Size)
SYSBFR EQU $0200 ;System Buffer SYSBFR EQU $0200 ;System Buffer
; $0281-$03FF ;Unused ; $0281-$03FF ;Unused
;Memory Mapped I/O ;Emulated BIOS System Calls
_KBHIT EQU $FFF0 ;Is a Key Pressed .GETCH EQU $FFE0 ;-K Read Keyboard
_GETCH EQU $FFF1 ;Read Keyboard (Blocking) .PUTCH EQU $FFE3 ;-C Write to Screen
FSCMD EQU $FFE6 ;-F filecmd() - File I/O Command Processor
SYSCMD EQU $FFE9 ;-S syscmd() - System Command Processor
XMCMD EQU $FFEC ;-E Extended Memory
.STDIO EQU $FFEF ;-M Memory Mapped stdio
EXIT EQU $FFF0 ;-X Exit Emulator
; $0000 ;-N NMI Vector
ARGV EQU $0300 ;Command Line Arguments Bu
ORG $0400 ;START at RAM midpoint ORG $0400 ;START at RAM midpoint
START: JMP MAIN ;Execute Program START: JMP MAIN ;Execute Program
;Read Character from Console ;Read Character from Console
GETKEY EQU $FFE0 ;Emulator _GETCH Routine GETKEY EQU .GETCH ;Emulator _GETCH Routine
;Poll Character from Keyboard ;Poll Character from Keyboard
POLKEY: BRK ;Exit Emulator POLKEY: BRK ;Exit Emulator
@ -58,7 +80,7 @@ GETCHR: JSR GETKEY ;Get Key from Console
RTS RTS
;Read Character from stdin ;Read Character from stdin
RDCHAR: LDA $FFEA ;Read Character from STDIN RDCHAR: LDA .STDIO ;Read Character from STDIN
CMP #$FF ;If EOF CMP #$FF ;If EOF
BNE RDCHAX BNE RDCHAX
LDA #0 ; Set to ASCII NUL LDA #0 ; Set to ASCII NUL
@ -80,16 +102,12 @@ NEWLIN: LDA #$0D ;Load Carriage Return into Accumulator
JMP PUTCHR ; and Print it JMP PUTCHR ; and Print it
;Print Character to Console ;Print Character to Console
PUTCHR EQU $FFE3 ;Emulator CHROUT Routine PUTCHR EQU .PUTCH ;Emulator CHROUT Routine
;Write Character to stdout ;Write Character to stdout
PRCHAR: STA $FFEA ;Read Character from STDIN PRCHAR: STA .STDIO ;Read Character from STDIN
RTS RTS
EXIT EQU $FFEC ;Emulator SHUTDN Routine
FSCMD EQU $FFE6 ;run6502 File System Command Routine
INCLUDE "prbyte.a02" ;PRBYTE and PRHEX routines INCLUDE "prbyte.a02" ;PRBYTE and PRHEX routines
INCLUDE "putstr.a02" ;PUTSTR routine INCLUDE "putstr.a02" ;PUTSTR routine

View File

@ -1,25 +1,26 @@
/* run6502 Header File */ /* run6502 Header File */
/* Platform Specific Settings */ /* Platform Specific Settings */
#pragma zeropage $50 $FF //Zero Page Free Space #pragma zeropage $40 $FF //Zero Page Free Space
/* Platform Specific Constants */ /* Platform Specific Constants */
#define DELKEY $08 //Delete/Backspace Key #define DELKEY $7F //Delete/Backspace Key
#define ESCKEY $1B //Escape/Stop Key #define ESCKEY $1B //Escape/Stop Key
#define RTNKEY $0D //Return/Enter Key #define RTNKEY $0D //Return/Enter Key
#define SYSBFL 128 //System Buffer Length #define SYSBFL 128 //System Buffer Length
/* Standard Library Variables */ /* Standard Library Variables */
zeropage int srcptr, dstptr; //Source and Destination Pointer zeropage int srcptr, dstptr; //Source and Destination Pointer
zeropage int blkptr, stkptr; //Block and Stack Pointers zeropage int blkptr, stkptr; //Block and Stack Pointers
zeropage int tmpptr, usrptr; //Temporary and User Pointer zeropage int tmpptr, lstptr, usrptr; //Temporary and User Pointer
int stkbgn, stkend; //Stack Begin and End Address int stkbgn, stkend; //Stack Begin and End Address
int blkbgn, blkend; //Block Begin and End Address int blkbgn, blkend; //Block Begin and End Address
char blklen, xmbank; //Block Segment Length, Ext Memory Bank char blklen, xmbank; //Block Segment Length, Ext Memory Bank
int xmaddr; //Extended Memory Address int xmaddr; //Extended Memory Address
char random, rdseed; //Pseudo-Random Number and Seed int intacc, intarg, intovr; //Integer Accumulator, Argument, Overflow
char temp0, temp1, temp2, temp3; //Temporary Storage char random, rdseed; //Pseudo-Random Number and Seed
char sysbfr[], sysbfp; //System String Buffer and Position char temp0, temp1, temp2, temp3; //Temporary Storage
char sysbfr[], sysbfp; //System String Buffer and Position
/* System Subroutines */ /* System Subroutines */
void delchr(); //Delete previous character void delchr(); //Delete previous character
@ -29,6 +30,7 @@ void newlin(); //Advance cursor to beginning of next line
char polkey(); //Poll Console for character char polkey(); //Poll Console for character
void prbyte(); //Print Accumulator as Hexadecimal number void prbyte(); //Print Accumulator as Hexadecimal number
void prhex(); //Print Low Nybble of Accumulator as Hex Digit void prhex(); //Print Low Nybble of Accumulator as Hex Digit
void prword(); //Print Low Nybble of Accumulator as Hex Digit
char putchr(); //Print ASCII character to Console char putchr(); //Print ASCII character to Console
char putstr(); //Print ASCII string to Console char putstr(); //Print ASCII string to Console

View File

@ -16,44 +16,70 @@ char s[128]; //Test String
char cval,cnum,ctot; //Character Function Variables char cval,cnum,ctot; //Character Function Variables
int ivar,ival; //Integer Variables int ivar,ival; //Integer Variables
int icmp,itot,ires; //Function Variables int ichk,itot,ires; //Function Variables
int less, more; //Test Values for imin() and imax() int less, more; //Test Values for imin() and imax()
int yx, dd; //Function Arguments and Variables int yx, dd; //Function Arguments and Variables
void cpival(icmp) { void cpcval(cnum) {
if (>ival <> >icmp or <ival <> <icmp) { if (cval <> cnum) {
putwrd(ival); puts("<>"); putwrd(icmp); puthex(cval); puts("<>"); puthex(cnum);
failln(); failln();
goto exit; goto exit;
} }
} }
/* Test imin() and imax() */ void cpival(ichk) {
void minmax() { if (>ival <> >ichk or <ival <> <ichk) {
prword(ival); puts("<>"); prword(ichk);
failln();
goto exit;
}
}
/* Test imin() and imax() and icmp() */
void minmax(ctot) {
newlin(); newlin();
puts("LESS=$"); putwrd(less); puts(",MORE=$"); putwrd(more); newlin(); puts("IMIN(IACC($"); prword(less); puts("),$"); prword(more); puts(")=$");
puts(" IMIN()=$"); setsrc(less); ival = imin(iacc(less),more); prword(ival); newlin();
ival = imin(more); putwrd(ival); newlin();
cpival(less); cpival(less);
puts(" IMAX()=$"); setsrc(less);
ival = imax(more); putwrd(ival); newlin(); puts("IMIN(IACC($"); prword(more); puts("),$"); prword(less); puts(")=$");
ival = imin(iacc(more),less); prword(ival); newlin();
cpival(less);
puts("IMAX(IACC($"); prword(less); puts("),$"); prword(more); puts(")=$");
iacc(less); ival = imax(more); prword(ival); newlin();
cpival(more); cpival(more);
puts("IMIN(IACC($"); prword(more); puts("),$"); prword(less); puts(")=$");
iacc(more); ival = imax(less); prword(ival); newlin();
cpival(more);
puts("ICMP(IACC($"); prword(less); puts("),$"); prword(more); puts(")=$");
cval = icmp(iacc(less),more); puthex(cval); newlin();
cpcval(-ctot);
puts("ICMP(IACC($"); prword(more); puts("),$"); prword(less); puts(")=$");
cval = icmp(iacc(more),less); puthex(cval); newlin();
cpcval(ctot);
} }
/* Test cvibcd() and upbcdi() */ /* Test cvibcd() and upbcdi() */
void intbcd(ival) { void intbcd(ival) {
newlin(); puts("CVIBCD($"); putwrd(ival); puts(")=$"); newlin(); puts("CVIBCD($"); prword(ival); puts(")=$");
cvibcd(ival); puthex(temp2); puthex(temp1); puthex(temp0); cvibcd(ival); puthex(temp2); puthex(temp1); puthex(temp0);
newlin(); puts("UPBCDI()=");
for (cnum=4; cnum:+; cnum--) {if(cnum<4) {putc(',');} putnyb(upbcdi(0,cnum));}
} }
/* Test itoa() and atoi() */ /* Test itoa() and atoi() */
void itaati(ivar) { void itaati(ivar) {
newlin(); //intbcd(ivar); newlin();
puts("ITOA($"); putwrd(ivar); puts(")=\""); puts("ITOA(IACC($"); prword(ivar); puts(",S); ");
setdst(s); size = itoa(ivar); puts(s); putln("\""); iacc(ivar); size = itoa(s); puts(" S=\""); puts(s); putln("\"");
puts("ATOI(\""); puts(s); puts("\")=$"); puts("ATOI(\""); puts(s); puts("\")=$");
ival = atoi(s); putwrd(ival); newlin(); ival = atoi(s); prword(ival); newlin();
cpival(ivar); cpival(ivar);
} }
@ -62,11 +88,11 @@ void itaati(ivar) {
void addsub(ivar) { void addsub(ivar) {
newlin(); newlin();
putint(ival); putc('+'); putint(ivar); putc('='); putint(ival); putc('+'); putint(ivar); putc('=');
setsrc(ival); ctot, itot = iadd(ivar); iacc(ival); ctot, itot = iadd(ivar);
putint(itot); puts(" carry=$"); puthex(ctot); newlin(); putint(itot); puts(", carry="); prhex(ctot); newlin();
putint(itot); putc('-'); putint(ivar); putc('='); putint(itot); putc('-'); putint(ivar); putc('=');
setsrc(itot); ires = isub(ivar); iacc(itot); ires = isub(ivar);
putint(itot); puts(" carry=$"); puthex(ctot); newlin(); putint(itot); puts(", carry="); prhex(ctot); newlin();
cpival(ires); cpival(ires);
} }
@ -74,15 +100,15 @@ void addsub(ivar) {
void mltdiv(ivar) { void mltdiv(ivar) {
newlin(); newlin();
putint(ival); putc('*'); putint(ivar); putc('='); putint(ival); putc('*'); putint(ivar); putc('=');
setdst(ival); cval,itot = imult(ivar); putint(itot); iacc(ival); cval,itot = imult(ivar); putint(itot);
if (cval) puts(" OVERFLOW!"); newlin(); if (cval) puts(" OVERFLOW!"); newlin();
putint(itot); putc('/'); putint(ivar); putc('='); putint(itot); putc('/'); putint(ivar); putc('=');
setdst(itot); ires = idiv(ivar); putint(ires); newlin(); iacc(itot); ires = idiv(ivar); putint(ires); newlin();
cpival(ires); cpival(ires);
ival>>; setsrc(ival); cval,itot = iadd(itot); ival>>; iacc(ival); cval,itot = iadd(itot);
if (cval) return; //Number to Large to Modulo if (cval) return; //Number to Large to Modulo
putint(itot); putc('%'); putint(ivar); putc('='); putint(itot); putc('%'); putint(ivar); putc('=');
setdst(itot); ires = imod(ivar); putint(ires); newlin(); iacc(itot); ires = imod(ivar); putint(ires); newlin();
cpival(ires); cpival(ires);
} }
@ -110,50 +136,55 @@ void shftlr(cval, ivar) {
cpival(itot); cpival(itot);
} }
main: main:
less = $009A; more = $00DE; minmax(); less = $009A; more = $00DE; minmax(1);
less = $789A; more = $78DE; minmax(); less = $789A; more = $78DE; minmax(1);
less = $7800; more = $BC00; minmax(); anykey();
less = $789A; more = $BCDE; minmax(); less = $7800; more = $BC00; minmax(1);
less = $F18F; more = $F18F; minmax(); less = $789A; more = $BCDE; minmax(1);
less = $F18F; more = $F18F; minmax(0);
anykey(); anykey();
itaati(&0); doasc:
itaati(&234); //itaati(&0);
itaati(&256); itaati(&234);
itaati(&456); itaati(&256);
itaati(&23456); itaati(&456);
itaati(&$FFFF); itaati(&23456);
anykey(); itaati(&$FFFF);
anykey();
ival = &23; addsub(&34); doadd:
ival = &1234; addsub(&5678); ival = &23; addsub(&34);
ival = &23456; addsub(&34567); ival = &1234; addsub(&5678);
ival = &$7700; addsub(&$6600); ival = &23456; addsub(&34567);
ival = &$7FFF; addsub(&$8000); ival = &$7700; addsub(&$6600);
ival = &$FDEC; addsub(&$CDEF); ival = &$7FFF; addsub(&$8000);
anykey(); ival = &$FDEC; addsub(&$CDEF);
anykey();
domlt:
ival = &23; mltdiv(&34);
ival = &123; mltdiv(&234);
ival = &255; mltdiv(&257);
anykey();
ival = &23; mltdiv(&34); doshft:
ival = &123; mltdiv(&234); shftlr(0,&$AA55);
ival = &255; mltdiv(&257); shftlr(1,&$A55A);
anykey(); shftlr(2,&$F00F);
shftlr(3,&$0FF0);
shftlr(0,&$AA55); shftlr(4,&$AA55);
shftlr(1,&$A55A); shftlr(7,&$A55A);
shftlr(2,&$F00F); anykey();
shftlr(3,&$0FF0);
shftlr(4,&$AA55);
shftlr(7,&$A55A);
anykey();
shftlr(8,&$AA55);
shftlr(9,&$A55A);
shftlr(11,&$0FF0);
shftlr(12,&$AA55);
shftlr(15,&$A55A);
shftlr(16,&$F00F);
shftlr(8,&$AA55);
shftlr(9,&$A55A);
shftlr(11,&$0FF0);
shftlr(12,&$AA55);
shftlr(15,&$A55A);
shftlr(16,&$F00F);
anykey();
goto exit; goto exit;